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 .