`OVER()` 子句讓聚合函數 (`SUM`、`AVG`、`MAX`、`MIN`) 與排名函數 (`ROW_NUMBER`、`RANK`、`DENSE_RANK`、`NTILE`) 能在不分組 (無 GROUP BY) 的情況下,針對每一列輸出分組統計值,極大簡化「各組最大值對應明細」等查詢。本文系統講解語法、兩大函數族群、分組統計實戰與分頁經典模式。
函數(...) OVER ( [ PARTITION BY 分組欄位 ] [ ORDER BY 排序欄位 ] )
| 函數 | 行為 | 並列處理 |
|---|---|---|
| ROW_NUMBER() | 唯一遞增序號 | 依 ORDER BY 細項打散 |
| RANK() | 同值同名次 | 名次跳號 (1,1,3) |
| DENSE_RANK() | 同值同名次 | 名次不跳 (1,1,2) |
| NTILE(n) | 等分 n 桶 | 桶號循環 |
WITH OrderInfo AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY OrderDate) AS RN,
OrderID, CustomerID, EmployeeID, OrderDate
FROM Orders
)
SELECT * FROM OrderInfo WHERE RN BETWEEN 1 AND 10; -- 第 1 頁,每頁 10 筆
支援 `SUM`、`AVG`、`MAX`、`MIN`、`COUNT` 等。只能用 PARTITION BY 或完全不分區。
DECLARE @t TABLE (
ProductID INT, ProductName VARCHAR(20), ProductType VARCHAR(20), Price INT
);
INSERT @t VALUES
(1,'name1','P1',3),(2,'name2','P1',5),
(3,'name3','P2',4),(4,'name4','P2',4);
-- 做法:OVER() 直接輸出各組最大價,再篩選
WITH cte AS (
SELECT
*,
MAX(Price) OVER (PARTITION BY ProductType) AS MaxPrice
FROM @t
)
SELECT ProductID, ProductName, ProductType, Price
FROM cte
WHERE Price = MaxPrice
ORDER BY ProductType;
優勢: 免 `JOIN` 衍生表、免 `GROUP BY` 再關聯、單掃描完成,可讀性高。
SELECT t1.*
FROM @t t1
JOIN (SELECT ProductType, MAX(Price) AS MaxPrice FROM @t GROUP BY ProductType) t2
ON t1.ProductType = t2.ProductType AND t1.Price = t2.MaxPrice;
SUM(Sales) OVER (
PARTITION BY Year
ORDER BY Month
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW -- 滾動 3 月加總
)
善用 `OVER()` 將分組統計從「多查詢 JOIN」簡化為「單查詢視窗」,是寫出高效、易維護 T-SQL 的關鍵技能。