sql >> Database teknologi >  >> RDS >> Database

Sådan vælger du den første række i hver gruppe efter gruppe

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 .


  1. Bedste praksis for løs kobling mellem data og brugergrænseflade i Android - Adapter, Filter, CursorLoader og ContentProvider

  2. PostgreSQL GROUP BY forskellig fra MySQL?

  3. Svarende til varchar(max) i MySQL?

  4. Ret "FEJL 1250 (42000):Tabel '...' fra en af ​​SELECT'erne kan ikke bruges i global ORDER-klausul", når du bruger UNION i MySQL