在 SQL Server 中,GROUP BY 遠不止簡單的分組聚合。透過 CUBE、ROLLUP 及 GROUPING SETS 等進階子句,我們能輕鬆產出多維度的彙總報表,滿足商業智慧分析的多樣化需求。本文將以實戰範例,帶您深入掌握這些強大功能的用法與差異。
首先,建立一張銷售資訊表 SalesInfo 並插入測試資料,模擬不同城市、不同年份的訂單記錄:
CREATE TABLE SalesInfo (
Ctiy NVARCHAR(50),
OrderDate DATETIME,
OrderID INT
);
INSERT INTO SalesInfo VALUES
(N'北京', '2014-06-09', 1001),
(N'北京', '2014-08-09', 1002),
(N'北京', '2013-10-09', 1009),
(N'大連', '2013-08-09', 4001),
(N'大連', '2013-10-09', 4002),
(N'大連', '2013-05-12', 4003),
(N'大連', '2014-11-11', 4004),
(N'大連', '2014-12-11', 4005);
WITH CUBE 會針對 GROUP BY 子句中指定的所有欄位組合,產生所有可能的彙總層級(即「超級聚合」)。
SELECT Ctiy, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY Ctiy
WITH CUBE;

結果會包含各城市的訂單數,以及一筆 Ctiy 為 NULL 的總計列,代表所有城市的訂單總數。
SELECT Ctiy, YEAR(OrderDate) AS OrderYear, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY Ctiy, YEAR(OrderDate)
WITH CUBE;

此時會產生:
• 各城市各年份的明細
• 各城市的年度小計
• 各年份的跨城市小計
• 總計
WITH ROLLUP 僅依 GROUP BY 欄位順序,產生階層式的彙總(由右至左遞減)。它不會產生所有排列組合,效能優於 CUBE。
SELECT Ctiy, YEAR(OrderDate) AS OrderYear, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY Ctiy, YEAR(OrderDate)
WITH ROLLUP;

結果包含:
• 城市 + 年份明細
• 各城市小計(年份為 NULL)
• 總計(城市與年份皆為 NULL)
注意:ROLLUP 的彙總層級取決於欄位順序,GROUP BY A, B, C 與 GROUP BY C, B, A 結果不同。
GROUP BY ALL 可強制顯示不符合 WHERE 條件的群組,其聚合值為 0 或 NULL。
SELECT Ctiy, COUNT(OrderID) AS OrderCount
FROM SalesInfo
WHERE Ctiy = N'大連'
GROUP BY ALL Ctiy;
雖然 WHERE 只篩選「大連」,但結果仍會列出「北京」,其 OrderCount 為 0。
限制:
ALL不能與CUBE、ROLLUP同時使用;若搭配HAVING,ALL功能將失效。
GROUP BY GROUPING SETS ((Ctiy), (YEAR(OrderDate)), ()),彈性指定所需彙總組合,語法更清晰、效能更佳。ROLLUP 或視窗函數。| 子句 | 彙總範圍 | 適用場景 | 效能 |
|---|---|---|---|
| CUBE | 所有欄位排列組合 | 多維度交叉分析、OLAP 報表 | 較高(組合數呈指數增長) |
| ROLLUP | 階層式(依欄位順序) | 層級報表(如:國家→省→市) | 中等 |
| GROUPING SETS | 自訂組合集合 | 精準控制所需彙總,最佳彈性 | 最佳(僅計算指定集合) |
| GROUP BY ALL | 強制顯示空群組 | 需呈現「無資料」群組的報表 | 低(舊語法,受限多) |
善用這些進階分組功能,能讓 T-SQL 直接產出豐富的彙總資料集,減少應用層的二次處理,大幅提升報表開發效率。