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, но до сих пор я получаю либо нулевые результаты, либо все содержимое таблицы.

Энди

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 может иметь только нулевые значения.

Вы можете использовать самостоятельное соединение, чтобы выбрать последнюю строку для каждого 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 выбрать все строки с максимальным созданием

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

РЕШИТЬ

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

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

        $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.

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

ВЫБЕРИТЕ p1.* ОТ product p1, product p2, где p1.CREATED_AT> п2.CREATED_AT сгруппировать по p2.UID

Вы можете достичь этого с eloquent с помощью orderBy() а также groupBy():

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

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

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

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

Это вернет все в таблице. Результаты будут упорядочены по убыванию столбца "create_at". Таким образом, первым результатом будет то, что вы ищете. Тогда "LIMIT" говорит вернуть только первый результат, чтобы у вас не было всей базы данных.

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

$model = new Model;
$model->select('*')->orderBy('created_at')->first();
Другие вопросы по тегам