SQL Server 2008 大幅增強彙總功能,語法風格更趨向 Oracle,提供 CUBE、ROLLUP、GROUPING SETS 等強大工具,能以單一查詢產出多維度統計報表,效能遠優於傳統多查詢聯合方式。本文以員工專案收入資料為例,逐步示範四大核心技巧。
USE testDb2;
GO
IF OBJECT_ID('tb_Income') IS NOT NULL DROP TABLE tb_Income;
GO
CREATE TABLE tb_Income(
TeamID INT NOT NULL,
PName NVARCHAR(20) NOT NULL,
CYear SMALLINT NOT NULL,
CMonth TINYINT NOT NULL,
CMoney DECIMAL(10,2) NOT NULL
);
GO
-- 插入測試資料(略,含胡一刀、苗人鳳、張無忌、趙半山、令狐沖等人員跨年月收入)
GROUP BY CUBE (col1, col2...) 會產生指定欄位所有可能組合的彙總列。例如:
SELECT TeamID AS 小組ID, PName AS 姓名, SUM(CMoney) AS 總收入
FROM tb_Income
GROUP BY CUBE (TeamID, PName);
結果包含:各小組各人員明細、各小組小計、各人員跨小組小計、總計。適用於需全方位「切片切塊」的 OLAP 報表。
GROUP BY ROLLUP (col1, col2...) 依欄位順序產生階層彙總(由細到粗)。欄位順序直接影響結果:
SELECT TeamID AS 小組ID, PName AS 姓名, SUM(CMoney) AS 總收入
FROM tb_Income
GROUP BY ROLLUP (TeamID, PName);
結果包含:明細 → 各小組各人員小計 → 各小組總計 → 總計。不包含「跨小組的人員小計」。適合固定鑽取路徑的報表(如:部門 → 員工)。
當 CUBE/ROLLUP 產生過多不需要的彙總列時,GROUPING SETS 允許精確指定所需組合:
SELECT TeamID AS 小組ID, PName AS 姓名, CYear AS 年份, SUM(CMoney) AS 總收入
FROM tb_Income
WHERE CMonth = 2
GROUP BY GROUPING SETS ((TeamID), (TeamID, PName), (CYear, PName));
僅產出三種彙總:按小組、按小組+人員、按年份+人員。極大減少資料傳輸與運算開銷。
面對含 NULL 的彙總列,如何區分「資料本身為 NULL」與「彙總產生的 NULL」?
SELECT TeamID AS 小組ID, CYear AS 年份,
CASE
WHEN GROUPING(TeamID)=0 AND GROUPING(CYear)=1 THEN '小組彙總'
WHEN GROUPING(TeamID)=1 AND GROUPING(CYear)=0 THEN '年份彙總'
WHEN GROUPING(TeamID)=1 AND GROUPING(CYear)=1 THEN '所有彙總'
ELSE '正常列'
END AS 列類別,
SUM(CMoney) AS 總收入
FROM tb_Income
GROUP BY CUBE (TeamID, CYear);
GROUPING(col):該欄位為彙總產生則回傳 1,否則 0。GROUPING_ID(col1, col2...):將多欄位 GROUPING 位元組合成整數,方便複雜邏輯判斷。| 語法 | 適用場景 | 彙總列數量 |
|---|---|---|
| CUBE | 多維度全排列分析,OLAP 切片 | 2^n (n=欄位數) |
| ROLLUP | 固定層級鑽取(地區→店點→產品) | n+1 |
| GROUPING SETS | 精確控制所需彙總組合,效能最佳 | 自訂 |
善用這三大功能,配合 GROUPING 函數識別列屬性,能以極簡潔的 T-SQL 完成複雜統計報表,是資料分析師與 BI 開發者的必備利器。