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