Я вижу, что многие люди используют для этого подзапросы или другие специфичные для поставщика функции, но я часто делаю этот тип запросов без подзапросов следующим образом. Он использует простой стандартный 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;
Re комментарий от @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.