OVER() 子句不僅限於排名函數,**聚合函數(SUM, AVG, MIN, MAX, COUNT)同樣支援**,可直接在明細列上顯示分組彙總值,避免自我 JOIN 或相關子查詢。
USE tempdb;
GO
IF OBJECT_ID('tb') IS NOT NULL DROP TABLE tb;
CREATE TABLE tb (name VARCHAR(10), val INT);
INSERT tb VALUES
('aa',10),('aa',20),('aa',20),('aa',30),
('bb',55),('bb',45),('bb',0);
SELECT
name, val,
-- 排名
排名 = RANK() OVER (PARTITION BY name ORDER BY val),
-- 佔比
佔比 = CAST(val * 1.0 / SUM(val) OVER (PARTITION BY name) AS DECIMAL(5,2)),
-- 距最大值
距最大 = val - MAX(val) OVER (PARTITION BY name),
-- 距最小值
距最小 = val - MIN(val) OVER (PARTITION BY name),
-- 距平均值
距平均 = val - AVG(val) OVER (PARTITION BY name)
FROM tb;
| name | val | 排名 | 佔比 | 距最大 | 距最小 | 距平均 |
|---|---|---|---|---|---|---|
| aa | 10 | 1 | 0.13 | -20 | 0 | -10.00 |
| aa | 20 | 2 | 0.25 | -10 | 10 | 0.00 |
| aa | 20 | 2 | 0.25 | -10 | 10 | 0.00 |
| aa | 30 | 4 | 0.38 | 0 | 20 | 10.00 |
| bb | 0 | 1 | 0.00 | -55 | 0 | -33.33 |
| bb | 45 | 2 | 0.45 | -10 | 45 | 11.67 |
| bb | 55 | 3 | 0.55 | 0 | 55 | 21.67 |
| 寫法 | 掃描次數 | 運算子 | 備註 |
|---|---|---|---|
| 相關子查詢 | N+1 (N=群組數) | Nested Loops + Spool | 每列觸發子查詢 |
| 自我 JOIN 彙總表 | 2 | Hash Match / Merge Join | 需建立衍生表 |
| OVER 窗口聚合 | 1 | Segment + Window Spool | 單次掃描、單一計畫 |
-- 僅 SQL 2012+ 支援 ROWS/RANGE 框架
SUM(val) OVER (PARTITION BY name ORDER BY val
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS RunningTotal
SQL 2005/2008/R2 僅支援 **完整分區框架**(等同 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),不支援排序後的滑動視窗。
ROW_NUMBER() OVER (PARTITION BY grp ORDER BY val DESC) <= NOVER 內不可再套用彙總函數(如 SUM(SUM(val)))。PARTITION BY 欄位建立索引可避免 Sort 運算子。WHERE / GROUP BY,需包裹 CTE/衍生表。