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:
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 è:
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;
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:
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;
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
.