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 資料表:

NameScore
張一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;

查詢結果:

NameScorerow_numrank_numdense_rank_num
張一95111
王二90222
李三90322
趙四85443

注意趙四的排名:

  • 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()