Problem:
Du har grupperet dine data med GROUP BY
og vil kun vise den første række fra hver gruppe.
Eksempel:
Vores database har en tabel med navnet exam_results
med data i følgende tabel:
fornavn | efternavn | år | resultat |
---|---|---|---|
John | Klein | 2020 | 40 |
Edith | Sort | 2020 | 43 |
Mark | Johnson | 2019 | 32 |
Laura | Sommer | 2020 | 35 |
Kate | Smith | 2019 | 41 |
Jacob | Sort | 2019 | 44 |
Tom | Bennett | 2020 | 38 |
Emily | Kelly | 2020 | 43 |
Lad os for hvert år finde den studerende med det bedste result
. Hvis der er to elever, der er de bedste i en gruppe, vælger vi vilkårligt en af dem til at vise.
Løsning:
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;
Resultatet er:
fornavn | efternavn | år | resultat | rækkenummer |
---|---|---|---|---|
Jacob | Sort | 2019 | 44 | 1 |
Emily | Kelly | 2020 | 43 | 1 |
Diskussion:
Først skal du skrive en CTE, hvor du tildeler et nummer til hver række inden for hver gruppe. For at gøre det kan du bruge ROW_NUMBER()
fungere. I OVER()
, angiver du de grupper, som rækkerne skal opdeles i (PARTITION BY
) og rækkefølgen, i hvilken numrene skal tildeles rækkerne (ORDER BY
).
Tag et kig på resultatet af den indre forespørgsel:
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
fornavn | efternavn | år | resultat | rækkenummer |
---|---|---|---|---|
Jacob | Sort | 2019 | 44 | 1 |
Kate | Smith | 2019 | 41 | 2 |
Mark | Johnson | 2019 | 32 | 3 |
Emily | Kelly | 2020 | 43 | 1 |
Edith | Sort | 2020 | 43 | 2 |
John | Klein | 2020 | 40 | 3 |
Tom | Bennett | 2020 | 38 | 4 |
Laura | Sommer | 2020 | 35 | 5 |
Du tildeler rækkenumrene inden for hver gruppe (dvs. år). Hver række har et rækkenummer baseret på værdien af result
kolonne. Rækkerne er sorteret i faldende rækkefølge på grund af DESC
søgeord efter ORDER BY result
. Selv hvis der er flere rækker i en gruppe, der har samme værdi af result
, rækkerne får stadig forskellige numre. Her har Edith Black og Emily Kelly det samme result
men forskellige rækkenumre. For at ændre denne adfærd og tildele det samme rækkenummer til det samme resultat inden for en gruppe, skal du bruge RANK()
eller DENSE_RANK()
i stedet for ROW_NUMBER()
.
I den ydre forespørgsel vælger du alle data fra CTE'en (added_row_number
) og brug en WHERE
betingelse for at angive, hvilken række der skal vises fra hver gruppe. Her ønsker vi at vise den første række, så betingelsen er row_number = 1
.
Bemærk, at du nemt kan ændre løsningen for at få f.eks. anden række af hver gruppe.
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;
Her er resultatet:
fornavn | efternavn | år | resultat | rækkenummer |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Edith | Sort | 2020 | 43 | 2 |
På den anden side, hvis du ønsker at få rækken/rækkerne med den næsthøjeste værdi af result
inden for hver gruppe skal du bruge DENSE_RANK()
fungere. Mens ROW_NUMBER()
funktionen opretter fortløbende tal for hver række i en gruppe, hvilket resulterer i forskellige værdier tildelt til rækkerne med det samme resultat, DENSE_RANK()
funktion giver det samme tal til rækkerne med samme resultat.
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;
fornavn | efternavn | år | resultat | rang |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
John | Klein | 2020 | 40 | 2 |
Du kan se, at John Klein har den næsthøjeste værdi af result (40)
for året 2020. John Klein er faktisk den tredje person i gruppen, men de første to elever har det samme result
og de har begge rank = 1
.