Problème :
Vous avez regroupé vos données avec GROUP BY
et souhaite afficher uniquement la première ligne de chaque groupe.
Exemple :
Notre base de données a une table nommée exam_results
avec les données dans le tableau suivant :
prénom | nom_de_famille | année | résultat |
---|---|---|---|
Jean | Klein | 2020 | 40 |
Édith | Noir | 2020 | 43 |
Marquer | Johnson | 2019 | 32 |
Laura | Été | 2020 | 35 |
Kate | Smith | 2019 | 41 |
Jacob | Noir | 2019 | 44 |
Tom | Bennett | 2020 | 38 |
Émilie | Kelly | 2020 | 43 |
Pour chaque année, trouvons l'étudiant avec le meilleur result
. S'il y a deux étudiants à égalité pour le meilleur dans un groupe, nous sélectionnerons arbitrairement l'un d'entre eux à afficher.
Solution :
WITH added_row_number AS ( SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results ) SELECT * FROM added_row_number WHERE row_number = 1;
Le résultat est :
prénom | nom_de_famille | année | résultat | numéro_ligne |
---|---|---|---|---|
Jacob | Noir | 2019 | 44 | 1 |
Émilie | Kelly | 2020 | 43 | 1 |
Discussion :
Tout d'abord, vous devez écrire un CTE dans lequel vous attribuez un numéro à chaque ligne de chaque groupe. Pour ce faire, vous pouvez utiliser le ROW_NUMBER()
une fonction. Dans OVER()
, vous spécifiez les groupes dans lesquels les lignes doivent être divisées (PARTITION BY
) et l'ordre dans lequel les numéros doivent être attribués aux lignes (ORDER BY
).
Jetez un œil au résultat de la requête interne :
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
prénom | nom_de_famille | année | résultat | numéro_ligne |
---|---|---|---|---|
Jacob | Noir | 2019 | 44 | 1 |
Kate | Smith | 2019 | 41 | 2 |
Marquer | Johnson | 2019 | 32 | 3 |
Émilie | Kelly | 2020 | 43 | 1 |
Édith | Noir | 2020 | 43 | 2 |
Jean | Klein | 2020 | 40 | 3 |
Tom | Bennett | 2020 | 38 | 4 |
Laura | Été | 2020 | 35 | 5 |
Vous attribuez les numéros de ligne dans chaque groupe (c'est-à-dire l'année). Chaque ligne a un numéro de ligne basé sur la valeur du result
colonne. Les lignes sont triées dans l'ordre décroissant à cause du DESC
mot-clé après ORDER BY result
. Même s'il y a plusieurs lignes dans un groupe qui ont la même valeur de result
, les lignes reçoivent toujours des numéros différents. Ici, Edith Black et Emily Kelly ont le même result
mais des numéros de lignes différents. Pour modifier ce comportement et attribuer le même numéro de ligne pour le même résultat au sein d'un groupe, utilisez RANK()
ou DENSE_RANK()
au lieu de ROW_NUMBER()
.
Dans la requête externe, vous sélectionnez toutes les données du CTE (added_row_number
) et utilisez un WHERE
condition pour spécifier quelle ligne afficher à partir de chaque groupe. Ici, nous voulons afficher la première ligne, donc la condition est row_number = 1
.
Notez que vous pouvez facilement modifier la solution pour obtenir, par exemple, la deuxième ligne de chaque groupe.
WITH added_row_number AS ( SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results ) SELECT * FROM added_row_number WHERE row_number = 2;
Voici le résultat :
prénom | nom_de_famille | année | résultat | numéro_ligne |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Édith | Noir | 2020 | 43 | 2 |
D'autre part, si vous souhaitez obtenir la ou les lignes avec la deuxième valeur la plus élevée de result
au sein de chaque groupe, vous devez utiliser le DENSE_RANK()
une fonction. Alors que le ROW_NUMBER()
la fonction crée des nombres consécutifs pour chaque ligne d'un groupe, ce qui donne différentes valeurs attribuées aux lignes avec le même résultat, le DENSE_RANK()
la fonction donne le même numéro aux lignes avec le même résultat.
WITH added_dense_rank AS ( SELECT *, DENSE_RANK() OVER(PARTITION BY year ORDER BY result DESC) AS rank FROM exam_results ) SELECT * FROM added_dense_rank WHERE rank = 2;
prénom | nom_de_famille | année | résultat | classement |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Jean | Klein | 2020 | 40 | 2 |
Vous pouvez voir que John Klein a la deuxième valeur la plus élevée de result (40)
pour l'année 2020. John Klein est en fait la troisième personne du groupe, mais les deux premiers élèves ont le même result
et ils ont tous les deux rank = 1
.