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

Come selezionare la prima riga in ogni gruppo GROUP BY

Problema:

Hai raggruppato i tuoi dati con GROUP BY e vorrei visualizzare solo la prima riga di ogni gruppo.

Esempio:

Il nostro database ha una tabella denominata exam_results con i dati nella tabella seguente:

anno
first_name cognome risultato
Giovanni Klein 2020 40
Modifica Nero 2020 43
Segna Johnson 2019 32
Laura Estate 2020 35
Kate Fabio 2019 41
Giacobbe Nero 2019 44
Tom Bennett 2020 38
Emilia Kelly 2020 43

Per ogni anno, troviamo lo studente con il miglior result . Se ci sono due studenti a pari merito in un gruppo, ne selezioneremo arbitrariamente uno da visualizzare.

Soluzione:

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;

Il risultato è:

anno
first_name cognome risultato numero_riga
Giacobbe Nero 2019 44 1
Emilia Kelly 2020 43 1

Discussione:

Innanzitutto, devi scrivere un CTE in cui assegni un numero a ciascuna riga all'interno di ciascun gruppo. Per farlo, puoi utilizzare il ROW_NUMBER() funzione. In OVER() , specifichi i gruppi in cui devono essere divise le righe (PARTITION BY ) e l'ordine in cui i numeri devono essere assegnati alle righe (ORDER BY ).

Dai un'occhiata al risultato della query interna:

SELECT
  *,
  ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
FROM exam_results;
anno
first_name cognome risultato numero_riga
Giacobbe Nero 2019 44 1
Kate Fabio 2019 41 2
Segna Johnson 2019 32 3
Emilia Kelly 2020 43 1
Modifica Nero 2020 43 2
Giovanni Klein 2020 40 3
Tom Bennett 2020 38 4
Laura Estate 2020 35 5

Assegni i numeri di riga all'interno di ciascun gruppo (ad esempio, anno). Ogni riga ha un numero di riga basato sul valore del result colonna. Le righe sono ordinate in ordine decrescente a causa di DESC parola chiave dopo ORDER BY result . Anche se all'interno di un gruppo sono presenti più righe che hanno lo stesso valore di result , alle righe vengono comunque assegnati numeri diversi. Qui, Edith Black ed Emily Kelly hanno lo stesso result ma numeri di riga diversi. Per modificare questo comportamento e assegnare lo stesso numero di riga per lo stesso risultato all'interno di un gruppo, usa RANK() o DENSE_RANK() invece di ROW_NUMBER() .

Nella query esterna, selezioni tutti i dati dal CTE (added_row_number ) e utilizzare un WHERE condizione per specificare quale riga visualizzare da ciascun gruppo. Qui, vogliamo visualizzare la prima riga, quindi la condizione è row_number = 1 .

Tieni presente che puoi facilmente modificare la soluzione per ottenere, ad esempio, la seconda riga di ogni gruppo.

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;

Ecco il risultato:

anno
first_name cognome risultato numero_riga
Kate Fabio 2019 41 2
Modifica Nero 2020 43 2

D'altra parte, se vuoi ottenere le righe con il secondo valore più alto di result all'interno di ogni gruppo, dovresti usare DENSE_RANK() funzione. Mentre il ROW_NUMBER() la funzione crea numeri consecutivi per ogni riga in un gruppo, risultando in valori diversi assegnati alle righe con lo stesso risultato, il DENSE_RANK() La funzione assegna lo stesso numero alle righe con lo stesso risultato.

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;
anno
first_name cognome risultato grado
Kate Fabio 2019 41 2
Giovanni Klein 2020 40 2

Puoi vedere che John Klein ha il secondo valore più alto di result (40) per l'anno 2020. John Klein è in realtà la terza persona del gruppo, ma i primi due studenti hanno lo stesso result ed entrambi hanno rank = 1 .