У меня есть таблица с сотнями записей для более чем 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, но пока что получаю либо нулевые результаты, либо все содержимое таблицы.
Энди
Не в этом случае нет. В каждой строке есть тонна обновленной информации по каждому UID, и мне нужна только последняя запись для каждого.






Это достаточно легко сделать в 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 Я не думаю, что нам здесь нужно делать LEFT JOIN, потому что каждый UID гарантированно будет иметь хотя бы одну запись, поступающую из подзапроса. В противном случае его все равно не существует.
Возможно, не по теме, но MAX(created_at) не будет рассматривать значения NULL, даже если он будет вставлен позже (id, который позже по своей природе)? Извините за не по теме, просто пытаюсь улучшить свои знания и выводы.
@Tpojka Хороший вопрос, я отредактировал свой ответ. Хотя я готов поспорить, что OP предположит, что каждому 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 выбирает все строки с max created_at
Группа Laravel Eloquent по последней записи
Вы, безусловно, направили меня по правильному пути своим ответом, большое спасибо. Я опубликую то, что я сделал, так как у меня также была ошибка нарушения, которую мне пришлось решить, связанную с GroupBy.
Вы должны использовать параметры 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+ продуктов, поэтому я не думаю, что ваш пример делает это.
Я не думаю, что так будет. Каждый UID имеет много записей, и существует более 1000 UID. Я хочу вернуть только ПОСЛЕДНЮЮ запись для КАЖДОГО UID, поэтому для каждого UID возвращалась только одна запись. Ваш пример просто вернет данные, отсортированные по created_at.
Ох, хорошо ! Затем просто добавьте ->groupBy('UID'), и он сделает работу
Спасибо за ответ, но это вызывает нарушение прав доступа. SQLSTATE [42000]: синтаксическая ошибка или нарушение прав доступа: 1055 Выражение № 1 списка SELECT не входит в предложение GROUP BY и содержит неагрегированный столбец. $ modelClass-> select ('*') -> orderBy ('created_at') -> groupBy ('UI D') -> first (); Я думаю, что описанный выше подход самосоединения может решить эту проблему, но пока не повезло :-)
затем замените метод groupBy()eloquent на метод unique(). Это должно сделать работу. Вот полный код, который должен работать: $model->orderBy('created_at')->get()->unique('UID');
SELECT p1.* FROM
productp1,productp2 where p1.CREATED_AT> p2.CREATED_ATgroup 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.
Еще раз спасибо.
Есть ли таблица продуктов с одной строкой для каждого продукта, связанная с этой таблицей? Это упростило бы визуализацию и управление, если бы вы использовали красноречивые