Vấn đề:
Bạn đã nhóm dữ liệu của mình với GROUP BY
và chỉ muốn hiển thị hàng đầu tiên từ mỗi nhóm.
Ví dụ:
Cơ sở dữ liệu của chúng tôi có một bảng có tên exam_results
với dữ liệu trong bảng sau:
first_name | last_name | năm | kết quả |
---|---|---|---|
John | Klein | 2020 | 40 |
Edith | Đen | 2020 | 43 |
Đánh dấu | Johnson | 2019 | 32 |
Laura | Mùa hè | 2020 | 35 |
Kate | Smith | 2019 | 41 |
Jacob | Đen | 2019 | 44 |
Tom | Bennett | 2020 | 38 |
Emily | Kelly | 2020 | 43 |
Đối với mỗi năm, hãy tìm học sinh có result
tốt nhất . Nếu có hai sinh viên được xếp vào hạng xuất sắc nhất trong một nhóm, chúng tôi sẽ tùy ý chọn một trong số họ để hiển thị.
Giải pháp:
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;
Kết quả là:
first_name | last_name | năm | kết quả | row_number |
---|---|---|---|---|
Jacob | Đen | 2019 | 44 | 1 |
Emily | Kelly | 2020 | 43 | 1 |
Thảo luận:
Đầu tiên, bạn cần viết một CTE trong đó bạn chỉ định một số cho mỗi hàng trong mỗi nhóm. Để làm điều đó, bạn có thể sử dụng ROW_NUMBER()
hàm số. Trong OVER()
, bạn chỉ định các nhóm mà các hàng sẽ được chia (PARTITION BY
) và thứ tự các số phải được gán cho các hàng (ORDER BY
).
Hãy xem kết quả của truy vấn bên trong:
SELECT *, ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number FROM exam_results;
first_name | last_name | năm | kết quả | row_number |
---|---|---|---|---|
Jacob | Đen | 2019 | 44 | 1 |
Kate | Smith | 2019 | 41 | 2 |
Đánh dấu | Johnson | 2019 | 32 | 3 |
Emily | Kelly | 2020 | 43 | 1 |
Edith | Đen | 2020 | 43 | 2 |
John | Klein | 2020 | 40 | 3 |
Tom | Bennett | 2020 | 38 | 4 |
Laura | Mùa hè | 2020 | 35 | 5 |
Bạn chỉ định số hàng trong mỗi nhóm (tức là năm). Mỗi hàng có một số hàng dựa trên giá trị của result
cột. Các hàng được sắp xếp theo thứ tự giảm dần do DESC
từ khóa sau ORDER BY result
. Ngay cả khi có nhiều hàng trong một nhóm có cùng giá trị result
, các hàng vẫn được cho các số khác nhau. Ở đây, Edith Black và Emily Kelly có cùng result
nhưng số hàng khác nhau. Để thay đổi hành vi này và chỉ định cùng một số hàng cho cùng một kết quả trong một nhóm, hãy sử dụng RANK()
hoặc DENSE_RANK()
thay vì ROW_NUMBER()
.
Trong truy vấn bên ngoài, bạn chọn tất cả dữ liệu từ CTE (added_row_number
) và sử dụng WHERE
điều kiện để chỉ định hàng sẽ hiển thị từ mỗi nhóm. Ở đây, chúng tôi muốn hiển thị hàng đầu tiên, vì vậy điều kiện là row_number = 1
.
Lưu ý rằng bạn có thể dễ dàng sửa đổi giải pháp để lấy, ví dụ: hàng thứ hai của mỗi nhóm.
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;
Đây là kết quả:
first_name | last_name | năm | kết quả | row_number |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
Edith | Đen | 2020 | 43 | 2 |
Mặt khác, nếu bạn muốn nhận (các) hàng có giá trị cao thứ hai trong tổng số result
trong mỗi nhóm, bạn nên sử dụng DENSE_RANK()
hàm số. Trong khi ROW_NUMBER()
hàm tạo các số liên tiếp cho mỗi hàng trong một nhóm, dẫn đến các giá trị khác nhau được gán cho các hàng có cùng kết quả, DENSE_RANK()
hàm cung cấp cùng một số cho các hàng có cùng kết quả.
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 | năm | kết quả | xếp hạng |
---|---|---|---|---|
Kate | Smith | 2019 | 41 | 2 |
John | Klein | 2020 | 40 | 2 |
Bạn có thể thấy rằng John Klein có giá trị cao thứ hai của result (40)
cho năm 2020. John Klein thực sự là người thứ ba trong nhóm, nhưng hai sinh viên đầu tiên có cùng result
và cả hai đều có rank = 1
.