Я вижу, что многие люди используют для этого подзапросы или специфичные для поставщика функции, но я часто делаю этот тип запросов без подзапросов следующим образом. Он использует простой стандартный SQL, поэтому он должен работать в любой марке СУБД.
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON (t1.UserId = t2.UserId AND t1."Date" < t2."Date")
WHERE t2.UserId IS NULL;
Другими словами: получить строку из t1
, где не существует другой строки с такой же UserId
и большей датой.
(Я поместил идентификатор «Дата» в разделители, потому что это зарезервированное слово SQL.)
В случае, если t1."Date" = t2."Date"
, появляется удвоение. Обычно таблицы имеют ключ auto_inc(seq)
, например, id
.
Во избежание дублирования можно использовать следующее:
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON t1.UserId = t2.UserId AND ((t1."Date" < t2."Date")
OR (t1."Date" = t2."Date" AND t1.id < t2.id))
WHERE t2.UserId IS NULL;
Комментарий от @Farhan:
Вот более подробное объяснение:
Внешнее соединение пытается присоединиться к t1
с t2
. По умолчанию возвращаются все результаты t1
, а , если в есть совпадение в t2
, также возвращается. Если в t2
нет совпадения для данной строки t1
, то запрос по-прежнему возвращает строку t1
и использует NULL
в качестве заполнителя для всех столбцов t2
. Так работают внешние соединения.
Хитрость в этом запросе состоит в том, чтобы спроектировать условие сопоставления объединения таким образом, чтобы t2
должно совпадать с таким же userid
и большим date
. Идея состоит в том, что если в t2
есть строка, имеющая большее date
, то строка в t1
, с которой она сравнивается с , не может быть самой большой date
для этого userid
. Но если нет совпадений - т.е. если в t2
нет строки с большим значением date
, чем в t1
- мы знаем, что строка в t1
была строкой с наибольшим значением date
для данного userid
.
В этих случаях (когда совпадений нет) столбцы t2
будут NULL
- даже столбцы, указанные в условии соединения. Вот почему мы используем WHERE t2.UserId IS NULL
, потому что мы ищем случаи, когда не было найдено ни одной строки с большим date
для данного userid
.