Je vois que beaucoup de gens utilisent des sous-requêtes ou bien des fonctionnalités spécifiques au fournisseur pour ce faire, mais je fais souvent ce type de requête sans sous-requêtes de la manière suivante. Il utilise du SQL standard simple et devrait donc fonctionner dans n'importe quelle marque de SGBDR.
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;
En d'autres termes: récupérer la ligne d' t1
où aucune autre ligne n'existe avec la même date UserId
et une date supérieure.
(J'ai mis l'identifiant "Date" dans les délimiteurs car c'est un mot réservé SQL.)
Dans le cas où t1."Date" = t2."Date"
, un doublement apparaît. Les tables ont généralement une auto_inc(seq)
clé, par exemple id
. Pour éviter le doublement peut être utilisé comme suit:
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 commentaire de @Farhan:
Voici une explication plus détaillée:
Une jointure externe tente de se joindre t1
à t2
. Par défaut, tous les résultats de t1
sont renvoyés et s'il y a une correspondance t2
, elle est également renvoyée. S'il n'y a pas de correspondance t2
pour une ligne donnée de t1
, la requête renvoie toujours la ligne de t1
et utilise NULL
comme espace réservé pour toust2
les colonnes de. C'est ainsi que les jointures externes fonctionnent en général.
L'astuce dans cette requête consiste à concevoir la condition de correspondance de la jointure telle qu'elle t2
doit correspondre à la même userid
et à une plus grande date
. L'idée étant que s'il existe une ligne t2
qui a un plus grand date
, alors la ligne dans laquelle t1
elle est comparée ne peut pas être la meilleure date
pour cela userid
. Mais s'il n'y a pas de correspondance - c'est-à-dire s'il n'y a pas de ligne t2
avec une plus grande date
que la ligne en t1
- nous savons que la ligne en t1
était la ligne avec le plus grand date
pour le donné userid
.
Dans ces cas (lorsqu'il n'y a pas de correspondance), les colonnes de t2
seront NULL
- même les colonnes spécifiées dans la condition de jointure. C'est pourquoi nous utilisons WHERE t2.UserId IS NULL
, car nous recherchons les cas où aucune ligne n'a été trouvée avec un plus grand date
pour le donné userid
.