排名需求常見於排行榜、分頁、Top-N 分析。本文系統介紹五種 T-SQL 排名實作,並深入解析「並列 (Tie)」的三種處理規則。
SELECT TOP 5 WITH TIES title_id, price, title_name
FROM title
ORDER BY price DESC;
價格並列者全部顯示,可能超過 5 筆 (範例返回 8 筆)。
CREATE VIEW ranked_sales AS
SELECT
(SELECT COUNT(DISTINCT T2.price) FROM title T2 WHERE T2.price >= T1.price) AS rank,
title_id, price, title_name
FROM title T1 WHERE price IS NOT NULL;
SELECT rank, title_id, price, title_name
FROM (
SELECT T1.title_id, T1.price, T1.title_name,
(SELECT COUNT(DISTINCT T2.price) FROM title T2 WHERE T1.price <= T2.price) AS rank
FROM title T1
) X
WHERE price IS NOT NULL
ORDER BY rank;
CREATE TABLE #ranked (rank int IDENTITY PRIMARY KEY, title_id char(6), price int, title_name varchar(30));
INSERT #ranked SELECT title_id, price, title_name FROM title WHERE price IS NOT NULL ORDER BY price DESC;
SELECT * FROM #ranked;
CREATE TABLE #ranked (rank int IDENTITY, title_id char(6), price int, title_name varchar(30));
INSERT #ranked SELECT title_id, price, title_name FROM title WHERE price IS NOT NULL ORDER BY price DESC;
SELECT B.rank, A.title_id, B.price, A.title_name
FROM (
SELECT MIN(T2.rank) AS rank, T2.price
FROM #ranked T2 GROUP BY T2.price
) B, #ranked A
WHERE A.price = B.price
ORDER BY B.rank;
並列項共享最小排名 (1,2,3,4,5,5,5,5,9…),下一名跳躍 (Gap),符合 **Olympic/競賽排名 (規則 3)**。
SELECT B.rank,
CASE B.number_tied WHEN 1 THEN '' ELSE '(' + CAST(B.number_tied AS varchar) + ' Way TIE)' END AS tie,
A.title_id, B.price, A.title_name
FROM (
SELECT MIN(T2.rank) AS rank, COUNT(*) AS number_tied, T2.price
FROM #ranked T2 GROUP BY T2.price
) B, #ranked A
WHERE A.price = B.price
ORDER BY B.rank;
三種並列規則對應三個游標實作:
| 規則 | 定義 | 排名序列範例 | |
|---|---|---|---|
| 規則 1 | 並列同排名,下一名遞增 1 | 1,2,3,4,5,5,5,5,6… | |
| 規則 2 | 每列唯一排名 (忽略並列) | 1,2,3,4,5,6,7,8,9… | |
| 規則 3 | 並列同排名,下一名依實際位置 (Gap) | 1,2,3,4,5,5,5,5,9… |
| 方法 | 適用場景 | 並列支援 | 效能 |
|---|---|---|---|
| 視圖/衍生表 | 小表、教學、跨平台 | 規則 3 | 慢 (N²) |
| 暫存表 + IDENTITY | 大表、不需並列語意 | 無 | 快 |
| 暫存表 + 分組 | 大表、需 Olympic 排名 | 規則 3 | 快 |
| 游標 | 複雜時序邏輯、逐列運算 | 三種皆可 | 中 (慢於暫存表) |
| SQL 2005+ 視窗函數 | 現代首選 | RANK/DENSE_RANK/ROW_NUMBER | 最佳 |
現代專案請直接使用 RANK() (規則 3)、DENSE_RANK() (規則 1)、ROW_NUMBER() (規則 2),語法簡潔、最佳化器支援最完善。本文保留傳統寫法供維護舊系統參考。