Problem:
Pogrupowałeś swoje dane za pomocą GROUP BY
i chciałby wyświetlić tylko pierwszy wiersz z każdej grupy.
Przykład:
Nasza baza danych zawiera tabelę o nazwie exam_results
z danymi w poniższej tabeli:
imię | nazwisko | rok | wynik |
---|---|---|---|
Jan | Klein | 2020 | 40 |
Edycja | Czarny | 2020 | 43 |
Zaznacz | Johnson | 2019 | 32 |
Laura | Lato | 2020 | 35 |
Kate | Kowalski | 2019 | 41 |
Jacob | Czarny | 2019 | 44 |
Tomek | Bennet | 2020 | 38 |
Emilia | Kelly | 2020 | 43 |
Na każdy rok znajdźmy ucznia z najlepszym result
. Jeśli w grupie remisuje dwóch uczniów, arbitralnie wybierzemy jednego do wyświetlenia.
Rozwiązanie:
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;
Wynik:
imię | nazwisko | rok | wynik | numer wiersza |
---|---|---|---|---|
Jacob | Czarny | 2019 | 44 | 1 |
Emilia | Kelly | 2020 | 43 | 1 |
Dyskusja:
Najpierw musisz napisać CTE, w którym przypiszesz numer do każdego wiersza w każdej grupie. Aby to zrobić, możesz użyć ROW_NUMBER()
funkcjonować. W OVER()
, określasz grupy, na które należy podzielić wiersze (PARTITION BY
) oraz kolejność przypisywania numerów do wierszy (ORDER BY
).
Spójrz na wynik wewnętrznego zapytania:
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
imię | nazwisko | rok | wynik | numer wiersza |
---|---|---|---|---|
Jacob | Czarny | 2019 | 44 | 1 |
Kate | Kowalski | 2019 | 41 | 2 |
Zaznacz | Johnson | 2019 | 32 | 3 |
Emilia | Kelly | 2020 | 43 | 1 |
Edycja | Czarny | 2020 | 43 | 2 |
Jan | Klein | 2020 | 40 | 3 |
Tomek | Bennet | 2020 | 38 | 4 |
Laura | Lato | 2020 | 35 | 5 |
Przypisujesz numery wierszy w każdej grupie (tj. rok). Każdy wiersz ma numer wiersza oparty na wartości result
kolumna. Wiersze są sortowane w kolejności malejącej ze względu na DESC
słowo kluczowe po ORDER BY result
. Nawet jeśli w grupie znajduje się wiele wierszy, które mają tę samą wartość result
, wiersze nadal mają różne numery. Tutaj Edith Black i Emily Kelly mają ten sam result
ale różne numery wierszy. Aby zmienić to zachowanie i przypisać ten sam numer wiersza dla tego samego wyniku w grupie, użyj RANK()
lub DENSE_RANK()
zamiast ROW_NUMBER()
.
W zapytaniu zewnętrznym wybierasz wszystkie dane z CTE (added_row_number
) i użyj WHERE
warunek, aby określić, który wiersz z każdej grupy ma być wyświetlany. Tutaj chcemy wyświetlić pierwszy wiersz, więc warunek to row_number = 1
.
Pamiętaj, że możesz łatwo zmodyfikować rozwiązanie, aby uzyskać na przykład drugi wiersz każdej grupy.
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;
Oto wynik:
imię | nazwisko | rok | wynik | numer wiersza |
---|---|---|---|---|
Kate | Kowalski | 2019 | 41 | 2 |
Edycja | Czarny | 2020 | 43 | 2 |
Z drugiej strony, jeśli chcesz uzyskać wiersze z drugą najwyższą wartością z result
w każdej grupie powinieneś użyć DENSE_RANK()
funkcjonować. Podczas gdy ROW_NUMBER()
funkcja tworzy kolejne liczby dla każdego wiersza w grupie, co skutkuje różnymi wartościami przypisanymi do wierszy z tym samym wynikiem, DENSE_RANK()
funkcja nadaje tę samą liczbę wierszom z tym samym wynikiem.
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;
imię | nazwisko | rok | wynik | ranking |
---|---|---|---|---|
Kate | Kowalski | 2019 | 41 | 2 |
Jan | Klein | 2020 | 40 | 2 |
Widać, że John Klein ma drugą najwyższą wartość result (40)
na rok 2020. John Klein jest w rzeczywistości trzecią osobą w grupie, ale dwóch pierwszych uczniów ma ten sam result
i obaj mają rank = 1
.