Je vois beaucoup de gens utiliser des sous-requêtes ou des fonctions de fenêtre 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 simple et standard, il 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 de t1
où aucune autre ligne n'existe avec le même UserId
et une date plus grande.
(J'ai mis l'identifiant "Date" entre les délimiteurs car c'est un mot réservé SQL.)
Au cas où si t1."Date" = t2."Date"
, le dédoublement apparaît. Habituellement, les tables ont auto_inc(seq)
clé, par ex. id
.Pour éviter le doublement peut être utilisé 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 joindre t1
avec t2
. Par défaut, tous les résultats de t1
sont renvoyés, et si il y a une correspondance dans t2
, il est également renvoyé. S'il n'y a pas de correspondance dans 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 l'ensemble de t2
les colonnes. C'est ainsi que fonctionnent les jointures externes en général.
L'astuce dans cette requête est de concevoir la condition de correspondance de la jointure telle que t2
doit correspondre au identique userid
, et un plus grand date
. L'idée étant de savoir si une ligne existe dans t2
qui a une date
supérieure , puis la ligne dans t1
c'est comparé à ne peut pas être le meilleur date
pour ce userid
. Mais s'il n'y a pas de correspondance -- c'est-à-dire si aucune ligne n'existe dans t2
avec une date
supérieure que la ligne dans t1
-- nous savons que la ligne dans t1
était la ligne avec la plus grande date
pour le userid
donné .
Dans ces cas (quand il n'y a pas de correspondance), les colonnes de t2
sera 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 une plus grande date
pour le userid
donné .