SQL Server 2005+ 引入視窗函數,ROW_NUMBER()、RANK()、DENSE_RANK() 可為查詢結果產生序號。本文說明三者差異、語法,並示範如何利用序號欄位合併多個結果集,提升查詢彈性。
SELECT
ROW_NUMBER() OVER (ORDER BY 欄位) AS RowIndex,
欄位1, 欄位2
FROM 資料表
OVER (ORDER BY ...):定義排序依據,必填。PARTITION BY 分組欄位 於 ORDER BY 之前,實現分組內排序。假設資料:Name 欄位值為 張三, 張三, 李四, 王五, 王五, 王五,依 Name 排序。
| 函數 | 結果序號 | 特性說明 |
|---|---|---|
ROW_NUMBER() |
1, 2, 3, 4, 5, 6 | 唯一連續流水號,不重複,適合分頁、匯出明細 |
RANK() |
1, 1, 3, 4, 4, 4 | 相同值同名次,下一名次跳過重複筆數(1,1 → 下一個是 3) |
DENSE_RANK() |
1, 1, 2, 3, 3, 3 | 相同值同名次,下一名次不跳過(1,1 → 下一個是 2) |
情境:需將「學生基本資料」與「學生成績」兩張表查詢結果,依學號合併為單一結果集回傳前端。
-- CTE 產生帶流水號的基本資料
WITH BaseData AS (
SELECT
ROW_NUMBER() OVER (ORDER BY StudentID) AS RowIndex,
StudentID, StudentName, ClassName
FROM Students
),
-- CTE 產生帶流水號的成績資料
ScoreData AS (
SELECT
ROW_NUMBER() OVER (ORDER BY StudentID) AS RowIndex,
StudentID, Subject, Score
FROM Scores
)
-- 以 RowIndex 為鍵 JOIN(前提:兩表排序欄位、筆數完全一致)
SELECT
b.StudentID, b.StudentName, b.ClassName,
s.Subject, s.Score
FROM BaseData b
INNER JOIN ScoreData s ON b.RowIndex = s.RowIndex
ORDER BY b.RowIndex;
以 RowIndex JOIN 極度脆弱:若兩表排序不一致、筆數不同、或中間插入/刪除資料,Join 即會錯位。生產環境請改用主鍵 (StudentID) JOIN:
SELECT s.StudentID, s.StudentName, s.ClassName, sc.Subject, sc.Score
FROM Students s
LEFT JOIN Scores sc ON s.StudentID = sc.StudentID
ORDER BY s.StudentID;
RowIndex 適合單一結果集的分頁、匯出 Excel 序號、臨時顯示,不適合作為跨結果集的關聯鍵。
SELECT
ClassName,
StudentName,
ROW_NUMBER() OVER (PARTITION BY ClassName ORDER BY Score DESC) AS ClassRank
FROM Students
ORDER BY ClassName, ClassRank;
產生各班級內依成績排名的流水號。
OVER (ORDER BY ...) 欄位有索引。ROW_NUMBER() 再外層篩選(如 WHERE RowIndex BETWEEN 10 AND 20),SQL Server 2012+ 請直接用 OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY。