Problém:
Seskupili jste svá data pomocí GROUP BY
a chtěli byste zobrazit pouze první řádek z každé skupiny.
Příklad:
Naše databáze obsahuje tabulku s názvem exam_results
s údaji v následující tabulce:
first_name | last_name | rok | výsledek |
---|---|---|---|
Jan | Klein | 2020 | 40 |
Edith | Černá | 2020 | 43 |
Označit | Johnson | 2019 | 32 |
Laura | Léto | 2020 | 35 |
Kate | Smith | 2019 | 41 |
Jacob | Černá | 2019 | 44 |
Tome | Bennett | 2020 | 38 |
Emily | Kelly | 2020 | 43 |
Pro každý rok najdeme studenta s nejlepším result
. Pokud jsou ve skupině dva studenti nerozhodně o nejlepšího, vybereme jednoho z nich k zobrazení.
Řešení:
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;
Výsledek je:
first_name | last_name | rok | výsledek | row_number |
---|---|---|---|---|
Jacob | Černá | 2019 | 44 | 1 |
Emily | Kelly | 2020 | 43 | 1 |
Diskuse:
Nejprve musíte napsat CTE, ve kterém přiřadíte číslo každému řádku v každé skupině. K tomu můžete použít ROW_NUMBER()
funkce. V OVER()
, určíte skupiny, do kterých mají být řádky rozděleny (PARTITION BY
) a pořadí, ve kterém mají být čísla přiřazena k řádkům (ORDER BY
).
Podívejte se na výsledek vnitřního dotazu:
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
first_name | last_name | rok | výsledek | row_number |
---|---|---|---|---|
Jacob | Černá | 2019 | 44 | 1 |
Kate | Smith | 2019 | 41 | 2 |
Označit | Johnson | 2019 | 32 | 3 |
Emily | Kelly | 2020 | 43 | 1 |
Edith | Černá | 2020 | 43 | 2 |
Jan | Klein | 2020 | 40 | 3 |
Tome | Bennett | 2020 | 38 | 4 |
Laura | Léto | 2020 | 35 | 5 |
V rámci každé skupiny (tj. roku) přiřadíte čísla řádků. Každý řádek má číslo řádku podle hodnoty result
sloupec. Řádky jsou seřazeny v sestupném pořadí kvůli DESC
klíčové slovo po ORDER BY result
. I když je ve skupině více řádků, které mají stejnou hodnotu result
, řádky mají stále jiná čísla. Zde mají Edith Black a Emily Kelly stejný result
ale jiná čísla řádků. Chcete-li toto chování změnit a přiřadit stejné číslo řádku pro stejný výsledek v rámci skupiny, použijte RANK()
nebo DENSE_RANK()
místo ROW_NUMBER()
.
Ve vnějším dotazu vyberete všechna data z CTE (added_row_number
) a použijte WHERE
podmínku určující, který řádek z každé skupiny se má zobrazit. Zde chceme zobrazit první řádek, takže podmínka je row_number = 1
.
Všimněte si, že řešení můžete snadno upravit, abyste získali například druhý řádek každé skupiny.
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;
Zde je výsledek:
first_name | last_name | rok | výsledek | row_number |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Edith | Černá | 2020 | 43 | 2 |
Na druhou stranu, pokud chcete získat řádek(y) s druhou nejvyšší hodnotou z result
v každé skupině byste měli použít DENSE_RANK()
funkce. Zatímco ROW_NUMBER()
funkce vytváří po sobě jdoucí čísla pro každý řádek ve skupině, což vede k různým hodnotám přiřazeným k řádkům se stejným výsledkem, DENSE_RANK()
funkce dává stejné číslo řádkům se stejným výsledkem.
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 | last_name | rok | výsledek | hodnocení |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Jan | Klein | 2020 | 40 | 2 |
Můžete vidět, že John Klein má druhou nejvyšší hodnotu result (40)
pro rok 2020. John Klein je ve skutečnosti třetí osobou ve skupině, ale první dva studenti mají stejný result
a oba mají rank = 1
.