Laravel - получить последнюю запись каждого типа UID

У меня есть таблица с сотнями записей для более чем 1000 различных продуктов, каждая из которых имеет уникальный UID.

ID  UID                 MANY COLUMNS    CREATED AT
1   dqwdwnboofrzrqww1   ...             2018-02-11 23:00:43
2   dqwdwnboofrzrqww1   ...             2018-02-12 01:15:30

3   dqwdwnbsha5drutj5   ...             2018-02-11 23:00:44
4   dqwdwnbsha5drutj5   ...             2018-02-12 01:15:31

5   dqwdwnbvhfg601jk1   ...             2018-02-11 23:00:45
6   dqwdwnbvhfg601jk1   ...             2018-02-12 01:15:33

...

Я хочу иметь возможность получать последнюю запись для каждого UID.

ID  UID                 MANY COLUMNS    CREATED AT
2   dqwdwnboofrzrqww1   ...             2018-02-12 01:15:30
4   dqwdwnbsha5drutj5   ...             2018-02-12 01:15:317
6   dqwdwnbvhfg601jk1   ...             2018-02-12 01:15:33

Возможно ли это за один вызов БД?

Я пробовал использовать DB, а также Eloquent, но пока что получаю либо нулевые результаты, либо все содержимое таблицы.

Энди

Есть ли таблица продуктов с одной строкой для каждого продукта, связанная с этой таблицей? Это упростило бы визуализацию и управление, если бы вы использовали красноречивые

apokryfos 11.03.2018 08:02

Не в этом случае нет. В каждой строке есть тонна обновленной информации по каждому UID, и мне нужна только последняя запись для каждого.

Andy 11.03.2018 08:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
0
2
1 299
6

Ответы 6

Это достаточно легко сделать в MySQL:

SELECT t1.*
FROM yourTable t1
INNER JOIN
(
    SELECT UID, MAX(created_at) AS max_created_at
    FROM yourTable
    GROUP BY UID
) t2
    ON t1.UID        = t2.UID AND
       t1.created_at = t2.max_created_at;

Перевод этого на Eloquent потребует некоторой работы, но, надеюсь, это даст вам хорошую отправную точку.

Обновлено: вы можете использовать LEFT JOIN, если ожидаете, что created_at может когда-либо быть NULLа также, что данный UID может иметь только нулевые созданные значения.

@Andy Убедитесь, что все последние записи created_at существуют.

Tpojka 11.03.2018 15:49

@Tpojka Я не думаю, что нам здесь нужно делать LEFT JOIN, потому что каждый UID гарантированно будет иметь хотя бы одну запись, поступающую из подзапроса. В противном случае его все равно не существует.

Tim Biegeleisen 11.03.2018 15:50

Возможно, не по теме, но MAX(created_at) не будет рассматривать значения NULL, даже если он будет вставлен позже (id, который позже по своей природе)? Извините за не по теме, просто пытаюсь улучшить свои знания и выводы.

Tpojka 11.03.2018 16:05

@Tpojka Хороший вопрос, я отредактировал свой ответ. Хотя я готов поспорить, что OP предположит, что каждому UID будет назначена дата создания.

Tim Biegeleisen 11.03.2018 16:18

Вы можете использовать самостоятельное соединение, чтобы выбрать последнюю строку для каждого UID.

select t.*
from yourTable t
left join yourTable t1 on t.uid = t1.uid
and t.created_at < t1.created_at 
where t1.uid is null

Используя конструктор запросов laravel, он будет похож на

DB::table('yourTable as t')
    ->select('t.*')
    ->leftJoin('yourTable as t1', function ($join) {
        $join->on('t.uid','=','t1.uid')
             ->where('t.created_at', '<', 't1.created_at');
    })
    ->whereNull('t1.uid')
    ->get();

Laravel Eloquent выбирает все строки с max created_at

Группа Laravel Eloquent по последней записи

Вы, безусловно, направили меня по правильному пути своим ответом, большое спасибо. Я опубликую то, что я сделал, так как у меня также была ошибка нарушения, которую мне пришлось решить, связанную с GroupBy.

Andy 11.03.2018 09:23

Вы должны использовать параметры ORDER BY и LIMITSQL, что приведет вас к простому запросу SQL:

например, в SQL у вас должно быть что-то вроде этого:

SELECT *
FROM table_name
ORDER BY `created_at` desc
LIMIT 1

Это вернет все в таблице. Результаты будут отсортированы по убыванию столбца created_at. Итак, первый результат будет тем, что вы ищете. Затем «LIMIT» сообщает, что нужно вернуть только первый результат, поэтому у вас не будет всей базы данных.

Если вы хотите сделать это красноречиво, вот код, делающий то же самое:

$model = new Model;
$model->select('*')->orderBy('created_at')->first();

Я хочу вернуть последнюю запись для ВСЕХ 1000+ продуктов, поэтому я не думаю, что ваш пример делает это.

Andy 11.03.2018 08:07

Я не думаю, что так будет. Каждый UID имеет много записей, и существует более 1000 UID. Я хочу вернуть только ПОСЛЕДНЮЮ запись для КАЖДОГО UID, поэтому для каждого UID возвращалась только одна запись. Ваш пример просто вернет данные, отсортированные по created_at.

Andy 11.03.2018 08:34

Ох, хорошо ! Затем просто добавьте ->groupBy('UID'), и он сделает работу

kevinniel 11.03.2018 08:55

Спасибо за ответ, но это вызывает нарушение прав доступа. SQLSTATE [42000]: синтаксическая ошибка или нарушение прав доступа: 1055 Выражение № 1 списка SELECT не входит в предложение GROUP BY и содержит неагрегированный столбец. $ modelClass-> select ('*') -> orderBy ('created_at') -> groupBy ('UI‌ D') -> first (); Я думаю, что описанный выше подход самосоединения может решить эту проблему, но пока не повезло :-)

Andy 11.03.2018 09:05

затем замените метод groupBy()eloquent на метод unique(). Это должно сделать работу. Вот полный код, который должен работать: $model->orderBy('created_at')->get()->unique('UID');

kevinniel 11.03.2018 09:09

SELECT p1.* FROM product p1, product p2 where p1.CREATED_AT> p2.CREATED_AT group by p2.UID

Вы можете добиться этого с помощью eloquent, используя orderBy() и groupBy():

$data = TblModel::orderBy('id','DESC')->groupBy('uid')->get();

Решено

Спасибо Тиму и М. Халиду за их ответы. Это привело меня к правильному пути, но я наткнулся на препятствие, поэтому я публикую это решение.

Это сработало:

        $allRowsNeeded = DB::table("table as s")
            ->select('s.*')
            ->leftJoin("table as s1", function ($join) {
                $join->on('s.uid', '=', 's1.uid');
                $join->on('s.created_at', '<', 's1.created_at');
            })
            ->whereNull('s1.uid')
            ->get();

Однако я получил нарушение прав доступа, поэтому мне пришлось зайти в config / database.php и установить

'strict' => false,

внутри конфигурации mysql, которая удаляет ONLY_FULL_GROUP_BY из SQL_MODE.

Еще раз спасибо.

Другие вопросы по теме