Ich sehe, dass viele Leute Unterabfragen oder andere Fensterfunktionen verwenden, um dies zu tun, aber ich mache diese Art von Abfrage oft ohne Unterabfragen auf die folgende Weise. Es verwendet einfaches, standardmäßiges SQL, sodass es in jeder RDBMS-Marke funktionieren sollte.
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;
Mit anderen Worten:Holen Sie die Zeile aus t1
wobei keine andere Zeile mit derselben UserId
vorhanden ist und ein größeres Datum.
(Ich habe den Bezeichner "Datum" in Trennzeichen gesetzt, weil es ein von SQL reserviertes Wort ist.)
Falls t1."Date" = t2."Date"
, Verdopplung erscheint. Normalerweise haben Tabellen auto_inc(seq)
Schlüssel, z. id
.Um eine Verdoppelung zu vermeiden, kann Folgendes verwendet werden:
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-Kommentar von @Farhan:
Hier ist eine ausführlichere Erklärung:
Ein äußerer Join versucht, t1
zu verbinden mit t2
. Standardmäßig alle Ergebnisse von t1
zurückgegeben werden, und if es gibt eine Übereinstimmung in t2
, es wird auch zurückgegeben. Wenn es keine Übereinstimmung in t2
gibt für eine bestimmte Zeile von t1
, dann gibt die Abfrage immer noch die Zeile von t1
zurück , und verwendet NULL
als Platzhalter für alles von t2
's Spalten. So funktionieren Outer Joins im Allgemeinen.
Der Trick bei dieser Abfrage besteht darin, die Übereinstimmungsbedingung des Joins so zu gestalten, dass t2
muss gleich übereinstimmen userid
, und ein größer date
. Die Idee ist, ob eine Zeile in t2
existiert das ein größeres date
hat , dann die Zeile in t1
es wird mit kann nicht verglichen das größte date
sein für diese userid
. Aber wenn es keine Übereinstimmung gibt – d. h. wenn keine Zeile in t2
existiert mit einem größeren date
als die Zeile in t1
-- wir wissen, dass die Zeile in t1
war die Zeile mit dem größten date
für die angegebene userid
.
In diesen Fällen (wenn es keine Übereinstimmung gibt), die Spalten von t2
wird NULL
sein -- sogar die in der Join-Bedingung angegebenen Spalten. Deshalb verwenden wir WHERE t2.UserId IS NULL
, weil wir nach den Fällen suchen, in denen keine Zeile mit einem größeren date
gefunden wurde für die angegebene userid
.