GROUP BY 不僅是簡單分組彙總,SQL Server 提供 CUBE、ROLLUP、GROUPING SETS、COMPUTE、ALL 等進階子句,支援多維度交叉分析、階層式小計與總計。本文透過實戰範例完整示範各子句行為差異。
CREATE TABLE SalesInfo
(
City 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);
產生所有分組欄位組合的彙總 (含總計)。
SELECT City, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY City WITH CUBE;
結果:各城市筆數 + 總計列 (City 為 NULL)。
SELECT City, YEAR(OrderDate) AS OrderYear, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY City, YEAR(OrderDate) WITH CUBE;
結果:(City, Year) 明細 + 各城市年度小計 + 各年度城市小計 + 總計。
依 GROUP BY 欄位順序產生階層小計,僅對第一個欄位產生總計。
SELECT City, YEAR(OrderDate) AS OrderYear, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY City, YEAR(OrderDate) WITH ROLLUP;
結果:(City, Year) 明細 + 各城市年度小計 + 總計 (無各年度跨城市小計)。
GROUP BY ALL 會顯示所有分組值,即使 WHERE 條件篩選掉該分組的資料列 (彙總值為 0)。
SELECT City, COUNT(OrderID) AS OrderCount
FROM SalesInfo
WHERE City = N'大連'
GROUP BY ALL City;
結果:顯示「北京」(筆數 0) 與「大連」(筆數 5)。
限制: ALL 不可與 CUBE/ROLLUP 同時使用;搭配 HAVING 時 ALL 失效。
注意: 此為舊版功能,現代應用建議改用 GROUPING SETS 或應用層處理。
SELECT City, OrderDate, OrderID
FROM SalesInfo
COMPUTE COUNT(OrderID);
輸出兩個結果集:明細資料 + 總筆數。
SELECT City, OrderDate, OrderID
FROM SalesInfo
ORDER BY City
COMPUTE COUNT(OrderID) BY City;
輸出多個結果集:依城市分組的明細 + 各城市小計。
SQL Server 2008+ 建議使用 GROUPING SETS 彈性定義彙總組合:
SELECT City, YEAR(OrderDate) AS OrderYear, COUNT(OrderID) AS OrderCount
FROM SalesInfo
GROUP BY GROUPING SETS
(
(City, YEAR(OrderDate)), -- 明細
(City), -- 城市小計
(YEAR(OrderDate)), -- 年度小計
() -- 總計
);
| 子句 | 彙總範圍 | 適用場景 | 備註 |
|---|---|---|---|
| CUBE | 所有組合 + 總計 | 多維度完整交叉分析 | 組合數 = 2^n,欄位多時結果集龐大 |
| ROLLUP | 階層式 + 總計 | 報表階層小計 (如 區域→城市→門市) | 欄位順序決定階層 |
| GROUPING SETS | 自訂組合 | 精確控制彙總粒度,效能最佳 | 現代標準語法 |
| ALL | 保留空分組 | 報表需顯示無資料分類 | 不可與 CUBE/ROLLUP 共用 |
| COMPUTE/BY | 結果集分離輸出 | 舊版報表工具相容 | 已棄用,不建議新專案使用 |
善用進階 GROUP BY 子句,能直接在資料庫層完成複雜的多維度彙總,減少應用層運算與資料傳輸量。