所有範例基於 `Sales.SalesOrderDetail` (明細) + `Sales.SalesOrderHeader` (主單)。
SELECT CarrierTrackingNumber,
SUM(LineTotal) AS TotalLine
FROM Sales.SalesOrderDetail
GROUP BY CarrierTrackingNumber;
SELECT CarrierTrackingNumber, SUM(LineTotal) AS TotalLine FROM Sales.SalesOrderDetail WHERE CarrierTrackingNumber = '48F2-4141-9A' GROUP BY CarrierTrackingNumber;
`WHERE` 在分組**前**過濾行,減少聚合輸入。
SELECT D.ProductID, H.OrderDate, SUM(D.LineTotal) AS TotalLine FROM Sales.SalesOrderDetail D JOIN Sales.SalesOrderHeader H ON D.SalesOrderID = H.SalesOrderID GROUP BY D.ProductID, H.OrderDate ORDER BY TotalLine DESC;
CREATE TABLE #NullTest (OrderDate DATE, Amount INT);
INSERT #NullTest VALUES (NULL,100), ('2024-10-30',100), ('2024-10-31',100), (NULL,100);
SELECT OrderDate, SUM(Amount) AS Total
FROM #NullTest
GROUP BY OrderDate;
-- 結果:NULL 群組合併為一行 (Total=200),SQL Server 視所有 NULL 相等。
DROP TABLE #NullTest;
SELECT CONVERT(CHAR(7), H.OrderDate, 120) AS YearMonth, -- yyyy-MM
SUM(D.LineTotal) AS TotalLine
FROM Sales.SalesOrderDetail D
JOIN Sales.SalesOrderHeader H ON D.SalesOrderID = H.SalesOrderID
GROUP BY CONVERT(CHAR(7), H.OrderDate, 120)
ORDER BY TotalLine DESC;
SELECT D.ProductID, H.OrderDate, SUM(D.LineTotal) AS TotalLine FROM Sales.SalesOrderDetail D JOIN Sales.SalesOrderHeader H ON D.SalesOrderID = H.SalesOrderID GROUP BY D.ProductID, H.OrderDate HAVING SUM(D.LineTotal) > 200000 ORDER BY TotalLine DESC;
-- 多維度小計一次搞定
SELECT
ISNULL(CAST(ProductID AS VARCHAR), 'ALL') AS ProductID,
ISNULL(CONVERT(CHAR(7), OrderDate, 120), 'ALL') AS YearMonth,
SUM(LineTotal) AS TotalLine,
GROUPING(ProductID) AS GP_Prod,
GROUPING(OrderDate) AS GP_Date
FROM Sales.SalesOrderDetail D
JOIN Sales.SalesOrderHeader H ON D.SalesOrderID = H.SalesOrderID
GROUP BY ROLLUP (ProductID, OrderDate); -- 或 CUBE, GROUPING SETS ((ProductID), (OrderDate), ())
`GROUP BY` 核心三要素:**分組鍵、聚合函數、過濾時機 (WHERE vs HAVING)**。掌握運算式分組、NULL 語義、ROLLUP/CUBE 多維小計,即可應對 90% 報表匯總需求。