Vidím, že mnoho lidí k tomu používá poddotazy nebo jiné funkce okna, ale často dělám tento druh dotazu bez poddotazů následujícím způsobem. Používá prostý standardní SQL, takže by měl fungovat v jakékoli značce 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;
Jinými slovy:načtěte řádek z t1
kde neexistuje žádný další řádek se stejným UserId
a větší Datum.
(Identifikátor "Datum" jsem vložil do oddělovačů, protože je to slovo vyhrazené SQL.)
V případě, že t1."Date" = t2."Date"
, objeví se zdvojení. Tabulky mají obvykle auto_inc(seq)
klíč, např. id
.Aby se zabránilo zdvojení, lze použít následující:
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;
Znovu komentář od @Farhan:
Zde je podrobnější vysvětlení:
Vnější spojení se pokusí připojit t1
s t2
. Ve výchozím nastavení jsou všechny výsledky t1
jsou vráceny a pokud existuje shoda v t2
, je také vrácen. Pokud v t2
není žádná shoda pro daný řádek t1
, pak dotaz stále vrací řádek t1
a používá NULL
jako zástupný symbol pro všechny t2
sloupce . Takto fungují vnější spojení obecně.
Trik v tomto dotazu je navrhnout podmínku shody spojení tak, že t2
musí odpovídat stejnému userid
a větší date
. Myšlenka je, zda existuje řádek v t2
který má větší date
, pak řádek v t1
je to porovnáno s nelze být největší date
pro toto userid
. Ale pokud neexistuje žádná shoda -- tj. pokud v t2
neexistuje žádný řádek s větším date
než řádek v t1
-- víme, že řádek v t1
byl řádek s největším date
pro dané userid
.
V těchto případech (když neexistuje žádná shoda), sloupce t2
bude NULL
-- dokonce i sloupce zadané v podmínce spojení. Proto používáme WHERE t2.UserId IS NULL
, protože hledáme případy, kdy nebyl nalezen žádný řádek s větším date
pro dané userid
.