RANK() 與 DENSE_RANK() 函數
RANK() 和 DENSE_RANK() 都是窗口函數中的排名函數,用來為查詢結果中的資料列指派排名。兩者的差別在於遇到相同值時,後續排名的處理方式不同。
RANK() 語法
RANK() OVER (
[PARTITION BY column_name(s)]
ORDER BY column_name(s)
)
RANK() 會在遇到相同值時給予相同排名,但之後的排名會「跳號」。
DENSE_RANK() 語法
DENSE_RANK() OVER (
[PARTITION BY column_name(s)]
ORDER BY column_name(s)
)
DENSE_RANK() (密集排名) 也會在遇到相同值時給予相同排名,但之後的排名「不跳號」,會連續編號。
RANK 與 DENSE_RANK 差異比較
假設我們有一個 students 資料表:
| Name | Score |
|---|---|
| 張一 | 95 |
| 王二 | 90 |
| 李三 | 90 |
| 趙四 | 85 |
使用三種排名函數來比較:
SELECT
Name,
Score,
ROW_NUMBER() OVER (ORDER BY Score DESC) AS row_num,
RANK() OVER (ORDER BY Score DESC) AS rank_num,
DENSE_RANK() OVER (ORDER BY Score DESC) AS dense_rank_num
FROM students;
查詢結果:
| Name | Score | row_num | rank_num | dense_rank_num |
|---|---|---|---|---|
| 張一 | 95 | 1 | 1 | 1 |
| 王二 | 90 | 2 | 2 | 2 |
| 李三 | 90 | 3 | 2 | 2 |
| 趙四 | 85 | 4 | 4 | 3 |
注意趙四的排名:
- ROW_NUMBER(): 4 (每列都是唯一編號)
- RANK(): 4 (因為有兩個第 2 名,所以跳過 3,直接是 4)
- DENSE_RANK(): 3 (不跳號,緊接著第 2 名就是第 3 名)
搭配 PARTITION BY 使用
可以在分組內各自排名:
SELECT
Name,
Dept,
Salary,
RANK() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS dept_rank
FROM employees;
這樣每個部門的薪資排名會各自從 1 開始計算。
實務應用:取各組前 N 名
找出各部門薪資前 3 名的員工:
SELECT Name, Dept, Salary
FROM (
SELECT
Name, Dept, Salary,
DENSE_RANK() OVER (PARTITION BY Dept ORDER BY Salary DESC) AS rk
FROM employees
) AS ranked
WHERE rk <= 3;
何時使用 RANK vs DENSE_RANK
| 情境 | 建議使用 |
|---|---|
| 需要知道「實際排在第幾位」 | RANK() |
| 需要連續的名次編號 | DENSE_RANK() |
| 體育競賽排名(並列後跳號) | RANK() |
| 分級制度(如 Top 10%) | DENSE_RANK() |