Widzę, że wiele osób używa do tego podzapytań lub funkcji okna, ale często wykonuję tego rodzaju zapytania bez podzapytań w następujący sposób. Używa zwykłego, standardowego SQL, więc powinien działać w każdej marce RDBMS.
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;
Innymi słowy:pobierz wiersz z t1
gdzie nie istnieje żaden inny wiersz z tym samym UserId
i większą datę.
(Umieściłem identyfikator „Data” w ogranicznikach, ponieważ jest to słowo zastrzeżone SQL.)
W przypadku, gdy t1."Date" = t2."Date"
, pojawia się podwojenie. Zwykle tabele mają auto_inc(seq)
klucz, np. id
.Aby uniknąć dublowania, można zastosować następujące:
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;
Ponownie komentarz od @Farhan:
Oto bardziej szczegółowe wyjaśnienie:
Złącze zewnętrzne próbuje dołączyć do t1
z t2
. Domyślnie wszystkie wyniki t1
są zwracane, a jeśli jest dopasowanie w t2
, to również jest zwracane. Jeśli nie ma dopasowania w t2
dla danego wiersza t1
, zapytanie nadal zwraca wiersz t1
i używa NULL
jako symbol zastępczy dla wszystkich t2
kolumny. Tak właśnie działają generalnie sprzężenia zewnętrzne.
Sztuczka w tym zapytaniu polega na zaprojektowaniu warunku dopasowania sprzężenia w taki sposób, że t2
musi pasować do tego samego userid
i większe date
. Chodzi o to, że wiersz istnieje w t2
który ma większą date
, a następnie wiersz w t1
jest porównywany z nie mogę bądź najlepszą date
dla tego userid
. Ale jeśli nie ma dopasowania -- tj. jeśli w t2
nie ma żadnego wiersza z większą date
niż wiersz w t1
-- wiemy, że wiersz w t1
był wiersz z największą date
dla podanego userid
.
W takich przypadkach (gdy nie ma dopasowania) kolumny t2
będzie NULL
-- nawet kolumny określone w warunku złączenia. Dlatego używamy WHERE t2.UserId IS NULL
, ponieważ szukamy przypadków, w których nie znaleziono wiersza z większą date
dla podanego userid
.