Widzę, że wiele osób korzysta z podkwerend lub funkcji specyficznych dla dostawców, aby to zrobić, ale często wykonuję tego rodzaju zapytania bez podkwerend w następujący sposób. Używa zwykłego, standardowego SQL, więc powinien działać w dowolnej 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 miejsca, w t1
którym nie istnieje żaden inny wiersz z tym samymUserId
i większej dacie.
(Umieszczam identyfikator „Data” w ogranicznikach, ponieważ jest to słowo zastrzeżone SQL).
W przypadku, gdy t1."Date" = t2."Date"
pojawi się podwojenie. Zwykle tabele mają auto_inc(seq)
klucz, np id
. Aby uniknąć podwojenia, można zastosować:
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 skomentuj @Farhan:
Oto bardziej szczegółowe wyjaśnienie:
Zewnętrzna próbach przyłączenia do przyłączenia t1
się t2
. Domyślnie t1
zwracane są wszystkie wyniki , a jeśli istnieje dopasowanie t2
, jest ono również zwracane. Jeśli nie ma dopasowania t2
dla danego wiersza t1
, wówczas zapytanie nadal zwraca wiersz t1
i używa NULL
jako symbolu zastępczego dla wszystkicht2
kolumn. Tak właśnie działają sprzężenia zewnętrzne.
Sztuczka w tym zapytaniu polega na zaprojektowaniu warunków dopasowania łączenia, które t2
muszą być takie same userid
i większe date
. Pomysł jest, jeśli wiersz istnieje t2
, że ma większą date
, wówczas wiersz t1
to jest porównywana nie może być największym date
na to userid
. Ale jeśli nie ma dopasowania - tj. Jeśli nie istnieje żaden wiersz t2
z wartością większą date
niż wiersz in t1
- wiemy, że wiersz w t1
był wierszem o największym date
dla danego userid
.
W tych przypadkach (gdy nie ma dopasowania), kolumny t2
będą NULL
- nawet kolumny określone w warunku łączenia. Dlatego używamy WHERE t2.UserId IS NULL
, ponieważ szukamy przypadków, w których nie znaleziono żadnego wiersza z większym date
dla podanego userid
.