JuniorLập trìnhSQL
Viết query trả về mức lương cao thứ hai
Thử trả lời trước
Đáp án mẫu
Query đơn giản và chạy được ở mọi engine là lấy giá trị lớn nhất trong những giá trị nhỏ hơn giá trị lớn nhất:
SELECT MAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);
Nó so sánh theo giá trị phân biệt, nên hai người cùng mức lương cao nhất không che mất mức thứ hai. Vì MAX không có GROUP BY luôn trả một dòng, kết quả là NULL khi không có mức lương thứ hai, thường đúng với điều bạn muốn.
Bản dùng window function mở rộng được cho mức cao thứ N:
SELECT DISTINCT salary
FROM (
SELECT salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rk
FROM employees
) t
WHERE rk = 2;
DENSE_RANK là hàm đúng ở đây, vì RANK sẽ nhảy cóc hạng sau các tie còn ROW_NUMBER thì đếm cả giá trị trùng. Bản này không trả dòng nào, thay vì NULL, khi giá trị không tồn tại.
LIMIT 1 OFFSET 1 nghe hấp dẫn nhưng sai khi mức lương cao nhất bị trùng, trừ khi bạn thêm DISTINCT.
Ý chính
- MAX của các giá trị nhỏ hơn MAX tổng chạy trên mọi engine
- DENSE_RANK xử lý tie và mở rộng cho giá trị thứ N
- Hai bản khác nhau khi không có mức lương thứ hai
Câu hỏi nối tiếp thường gặp
- Bạn lấy mức lương cao thứ hai của từng phòng ban như thế nào?
Lỗi thường gặp
- Dùng LIMIT 1 OFFSET 1 mà không có DISTINCT khi lương bị trùng
- Dùng ROW_NUMBER và tính các mức lương trùng thành các hạng khác nhau