Проблем:
Групирате данните си с GROUP BY и би искал да показва само първия ред от всяка група.
Пример:
Нашата база данни има таблица с име exam_results с данни в следната таблица:
| first_name | фамилно_име | година | резултат |
|---|---|---|---|
| Джон | Клайн | 2020 | 40 |
| Едит | Черно | 2020 | 43 |
| Отметка | Джонсън | 2019 | 32 |
| Лора | Лято | 2020 | 35 |
| Кейт | Смит | 2019 | 41 |
| Якоб | Черно | 2019 | 44 |
| Том | Бенет | 2020 | 38 |
| Емили | Кели | 2020 | 43 |
За всяка година нека намерим ученика с най-добрия result . Ако в група има двама ученици, изравнени за най-добрия, ние произволно ще изберем един от тях за показване.
Решение:
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;
Резултатът е:
| first_name | фамилно_име | година | резултат | номер_ред |
|---|---|---|---|---|
| Якоб | Черно | 2019 | 44 | 1 |
| Емили | Кели | 2020 | 43 | 1 |
Дискусия:
Първо, трябва да напишете CTE, в който да присвоите номер на всеки ред във всяка група. За да направите това, можете да използвате ROW_NUMBER() функция. В OVER() , посочвате групите, на които трябва да бъдат разделени редовете (PARTITION BY ) и реда, в който числата трябва да бъдат присвоени на редовете (ORDER BY ).
Разгледайте резултата от вътрешната заявка:
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
| first_name | фамилно_име | година | резултат | номер_ред |
|---|---|---|---|---|
| Якоб | Черно | 2019 | 44 | 1 |
| Кейт | Смит | 2019 | 41 | 2 |
| Отметка | Джонсън | 2019 | 32 | 3 |
| Емили | Кели | 2020 | 43 | 1 |
| Едит | Черно | 2020 | 43 | 2 |
| Джон | Клайн | 2020 | 40 | 3 |
| Том | Бенет | 2020 | 38 | 4 |
| Лора | Лято | 2020 | 35 | 5 |
Вие задавате номерата на редовете във всяка група (т.е. година). Всеки ред има номер на ред въз основа на стойността на result колона. Редовете са сортирани в низходящ ред поради DESC ключова дума след ORDER BY result . Дори ако има няколко реда в рамките на група, които имат една и съща стойност на result , редовете все още получават различни номера. Тук Едит Блек и Емили Кели имат същия result но различни номера на редовете. За да промените това поведение и да зададете същия номер на ред за същия резултат в рамките на група, използвайте RANK() или DENSE_RANK() вместо ROW_NUMBER() .
Във външната заявка избирате всички данни от CTE (added_row_number ) и използвайте WHERE условие, за да посочите кой ред да се показва от всяка група. Тук искаме да покажем първия ред, така че условието е row_number = 1 .
Имайте предвид, че можете лесно да промените решението, за да получите например втория ред от всяка група.
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;
Ето резултата:
| first_name | фамилно_име | година | резултат | номер_ред |
|---|---|---|---|---|
| Кейт | Смит | 2019 | 41 | 2 |
| Едит | Черно | 2020 | 43 | 2 |
От друга страна, ако искате да получите редовете с втората най-висока стойност на result във всяка група трябва да използвате DENSE_RANK() функция. Докато ROW_NUMBER() функцията създава последователни числа за всеки ред в група, което води до различни стойности, присвоени на редовете със същия резултат, DENSE_RANK() функция дава едно и също число на редовете със същия резултат.
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 | фамилно_име | година | резултат | ранг |
|---|---|---|---|---|
| Кейт | Смит | 2019 | 41 | 2 |
| Джон | Клайн | 2020 | 40 | 2 |
Можете да видите, че Джон Клайн има втората най-висока стойност на result (40) за 2020 г. Джон Клайн всъщност е третото лице в групата, но първите двама ученици имат същия result и двете имат rank = 1 .