Oracle
 sql >> Base de données >  >> RDS >> Oracle

Récupérer la ligne qui a la valeur Max pour une colonne

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é .