首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> SQL Server 2005

SQL Server 2005 窗口函數精講:ROW_NUMBER、RANK、DENSE_RANK 語法、差異與實戰對比

     編輯:SQL Server 2005

三大排序窗口函數對比

函數行為並列處理編號連續性
ROW_NUMBER()分區內唯一遞增序號不產生並列,強制 1,2,3...連續無間隙
RANK()並列同名次,下一名次跳過並列數並列同名次 (如 1,1,3)有間隙
DENSE_RANK()並列同名次,下一名次緊接並列同名次 (如 1,1,2)連續無間隙

通用語法

FUNCTION() OVER ( [PARTITION BY partition_column_list] ORDER BY order_column_list )
  • PARTITION BY:分組,每組獨立編號 (可省略,視為單一分區)。
  • ORDER BY:必填,決定編號順序。

範例資料

CREATE TABLE rankorder(orderid INT, qty INT);
INSERT rankorder VALUES (30001,10),(10001,10),(10006,10),(40005,10),
                        (30003,15),(30004,20),(20002,20),(20001,20),
                        (10005,30),(30007,30),(40001,40),(30007,30);

單欄排序 (ORDER BY qty) 結果對比

SELECT orderid, qty,
       ROW_NUMBER() OVER(ORDER BY qty) AS rownumber,
       RANK() OVER(ORDER BY qty) AS rank,
       DENSE_RANK() OVER(ORDER BY qty) AS denserank
FROM rankorder
ORDER BY qty;

結果:

orderidqtyrownumberrankdenserank
3000110111
1000110211
1000610311
4000510411
3000315552
3000420663
2000220763
2000120863
1000530994
30007301094
30007301194
400014012125

觀察:qty=10 四筆並列,ROW_NUMBER 強制 1-4,RANK 全部 1,下一名次跳到 5;DENSE_RANK 全部 1,下一名次為 2。

雙欄排序 (ORDER BY qty, orderid) 結果

SELECT orderid, qty,
       ROW_NUMBER() OVER(ORDER BY qty, orderid) AS rownumber,
       RANK() OVER(ORDER BY qty, orderid) AS rank,
       DENSE_RANK() OVER(ORDER BY qty, orderid) AS denserank
FROM rankorder
ORDER BY qty, orderid;

因 orderid 唯一,三函數結果完全一致 (1-12 連續),無並列。

實戰應用場景

  • 分頁:ROW_NUMBER() 配合 CTE (WHERE rn BETWEEN @start AND @end)。
  • 去重保留最新:ROW_NUMBER() OVER (PARTITION BY key ORDER BY date DESC) = 1。
  • 排名報表:銷售業績排名用 RANK() (並列同名次) 或 DENSE_RANK() (連續名次)。
  • Top-N per Group:各分類取前 N 筆,WHERE rn <= N。

AdventureWorks 官方範例 (節錄)

-- ROW_NUMBER: 依 SalesYTD 排名業務員
SELECT c.FirstName, c.LastName,
       ROW_NUMBER() OVER(ORDER BY s.SalesYTD DESC) AS 'Row Number',
       s.SalesYTD, a.PostalCode
FROM Sales.SalesPerson s
JOIN Person.Contact c ON s.SalesPersonID = c.ContactID
JOIN Person.Address a ON a.AddressID = c.ContactID
WHERE TerritoryID IS NOT NULL AND SalesYTD <> 0;

-- RANK: 依庫存量量對產品排名 (按 LocationID 分區)
SELECT i.ProductID, p.Name, i.LocationID, i.Quantity,
       RANK() OVER(PARTITION BY i.LocationID ORDER BY i.Quantity) AS RANK
FROM Production.ProductInventory i
JOIN Production.Product p ON i.ProductID = p.ProductID
ORDER BY p.Name;

-- DENSE_RANK: 同上但名次連續
SELECT i.ProductID, p.Name, i.LocationID, i.Quantity,
       DENSE_RANK() OVER(PARTITION BY i.LocationID ORDER BY i.Quantity) AS DENSE_RANK
FROM Production.ProductInventory i
JOIN Production.Product p ON i.ProductID = p.ProductID
ORDER BY p.Name;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved