Problem:
Du har grupperat dina data med GROUP BY
och vill bara visa den första raden från varje grupp.
Exempel:
Vår databas har en tabell som heter exam_results
med data i följande tabell:
förnamn | efternamn | år | resultat |
---|---|---|---|
John | Klein | 2020 | 40 |
Edith | Svart | 2020 | 43 |
Markera | Johnson | 2019 | 32 |
Laura | Sommar | 2020 | 35 |
Kate | Smith | 2019 | 41 |
Jacob | Svart | 2019 | 44 |
Tom | Bennett | 2020 | 38 |
Emily | Kelly | 2020 | 43 |
För varje år, låt oss hitta studenten med det bästa result
. Om det finns två elever som är de bästa i en grupp, väljer vi godtyckligt en av dem att visa.
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 är:
förnamn | efternamn | år | resultat | radnummer |
---|---|---|---|---|
Jacob | Svart | 2019 | 44 | 1 |
Emily | Kelly | 2020 | 43 | 1 |
Diskussion:
Först måste du skriva en CTE där du tilldelar ett nummer till varje rad inom varje grupp. För att göra det kan du använda ROW_NUMBER()
fungera. I OVER()
, anger du grupperna som raderna ska delas in i (PARTITION BY
) och i vilken ordning numren ska tilldelas raderna (ORDER BY
).
Ta en titt på resultatet av den inre frågan:
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
förnamn | efternamn | år | resultat | radnummer |
---|---|---|---|---|
Jacob | Svart | 2019 | 44 | 1 |
Kate | Smith | 2019 | 41 | 2 |
Markera | Johnson | 2019 | 32 | 3 |
Emily | Kelly | 2020 | 43 | 1 |
Edith | Svart | 2020 | 43 | 2 |
John | Klein | 2020 | 40 | 3 |
Tom | Bennett | 2020 | 38 | 4 |
Laura | Sommar | 2020 | 35 | 5 |
Du tilldelar radnumren inom varje grupp (d.v.s. år). Varje rad har ett radnummer baserat på värdet på result
kolumn. Raderna sorteras i fallande ordning på grund av DESC
sökord efter ORDER BY result
. Även om det finns flera rader inom en grupp som har samma värde på result
, raderna får fortfarande olika nummer. Här har Edith Black och Emily Kelly samma result
men olika radnummer. För att ändra detta beteende och tilldela samma radnummer för samma resultat inom en grupp, använd RANK()
eller DENSE_RANK()
istället för ROW_NUMBER()
.
I den yttre frågan väljer du all data från CTE (added_row_number
) och använd en WHERE
villkor för att ange vilken rad som ska visas från varje grupp. Här vill vi visa den första raden, så villkoret är row_number = 1
.
Observera att du enkelt kan modifiera lösningen för att få till exempel den andra raden för varje grupp.
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;
Här är resultatet:
förnamn | efternamn | år | resultat | radnummer |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Edith | Svart | 2020 | 43 | 2 |
Å andra sidan, om du vill få raden/raderna med det näst högsta värdet av result
inom varje grupp bör du använda DENSE_RANK()
fungera. Medan ROW_NUMBER()
funktionen skapar på varandra följande tal för varje rad i en grupp, vilket resulterar i olika värden som tilldelas raderna med samma resultat, DENSE_RANK()
funktion ger samma nummer till raderna med samma 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;
förnamn | efternamn | år | resultat | rang |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
John | Klein | 2020 | 40 | 2 |
Du kan se att John Klein har det näst högsta värdet på result (40)
för år 2020. John Klein är faktiskt den tredje personen i gruppen, men de två första eleverna har samma result
och de har båda rank = 1
.