使用 GROUP BY 摘要數據
雖然聚合函數對分析很有用,但您可能想要先將數據排列成子集,再加以摘要。 在本節中,您將瞭解如何使用 GROUP BY 子句來完成這項工作。
使用 GROUP BY 子句
如您所了解,當您的 SELECT 語句經過處理時,在評估FROM子句和 WHERE 子句之後,就會建立虛擬數據表。 虛擬數據表的內容現在可供進一步處理。 您可以使用 GROUP BY 子句,將這個虛擬數據表的內容細分成數據列群組。
若要將資料列分組,請在 GROUP BY 子句中指定一或多個元素:
GROUP BY <value1> [, <value2>, …]
GROUP BY 會建立群組,並將數據列放入每個群組中,如 子句中指定的專案所決定。
例如,下列查詢會產生一組群組的數據列,也就是 Sales.SalesOrderHeader 數據表中每個 CustomerID 一個數據列。 另一種查看 GROUP BY 程式的方式是 ,CustomerID 具有相同值的所有數據列都會分組在一起,並在單一結果列中傳回。
SELECT CustomerID
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
上述查詢相當於下列查詢:
SELECT DISTINCT CustomerID
FROM Sales.SalesOrderHeader
處理 GROUP BY 子句且每個數據列都已與群組相關聯之後,查詢的後續階段必須匯總 SELECT 清單中任何源數據列的元素,但不會出現在 GROUP BY 清單中。 這項需求會影響您撰寫SELECT和 HAVING 子句的方式。
那麼,使用 GROUP BY 或 DISTINCT 撰寫查詢有何差異? 如果您想要知道的只是 CustomerID 的相異值,則沒有任何差異。 但是使用 GROUP BY,我們可以將其他元素新增至 SELECT 清單,然後針對每個群組匯總。
最簡單的聚合函數是 COUNT>。 下列查詢會根據 CustomerID 值,從 CustomerID 擷取原始的 830 個源數據列,並將其分組為 89 個群組。 每個相異 CustomerID 值都會在 GROUP BY 查詢中產生一個輸出數據列
SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
針對每個 CustomerID 值,查詢會匯總並計算數據列,因此結果會顯示 SalesOrderHeader 數據表中有多少個數據列屬於每個客戶。
客戶編號
OrderCount
1234
3
1005
1
請注意,GROUP BY 不保證結果的順序。 通常,由於查詢處理器執行群組作業的方式,結果會依群組值的順序傳回。 不過,您不應該依賴此行為。 如果您需要排序結果,您必須明確包含 ORDER 子句:
SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY CustomerID;
這次,結果會以指定的順序傳回:
客戶編號
OrderCount
1005
1
1234
3
SELECT 語句中的 子句會依下列順序套用:
- 來自
- 哪裡
- GROUP BY
- 擁有
- SELECT
- 排序依據
數據行別名會在 SELECT 子句中指派,這會在 GROUP BY 子句 之後 ,但在 ORDER BY 子句 之前 發生。 您可以在 ORDER BY 子句中參考數據行別名,但無法在 GROUP BY 子句中參考。 下列查詢會導致 資料列名稱錯誤無效 :
SELECT CustomerID AS Customer,
COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY Customer
ORDER BY Customer;
不過,下列查詢將會成功,並依客戶標識元分組和排序結果。
SELECT CustomerID AS Customer,
COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY Customer;
針對 GROUP BY 錯誤進行疑難解答
在 SELECT 語句中使用 GROUP BY 時,常見的障礙在於了解發生下列錯誤訊息類型的原因:
Msg 8120、Level 16、State 1、Line 2 Column <column_name> 在選取清單中無效,因為它不包含在聚合函數或 GROUP BY 子句中。
例如,允許下列查詢,因為 SELECT 清單中的每一個數據行都是 GROUP BY 子句中的數據行,或是在每個群組上運作的聚合函數:
SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
下列查詢會傳回錯誤,因為 PurchaseOrderNumber 不是 GROUP BY 的一部分,而且不會與聚合函數搭配使用。
SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
此查詢會傳回錯誤:
Msg 8120, Level 16, State 1, Line 1
Column 'Sales.SalesOrderHeader.PurchaseOrderNumber' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
以下是另一種思考方式。 此查詢會針對每個 CustomerID 值傳回一個數據列。 但是,相同 CustomerID 的數據列可以有不同的 PurchaseOrderNumber 值,因此應該傳回哪些值?
如果您想要查看每個客戶標識符和每個採購單的訂單,您可以將 PurchaseOrderNumber 數據行新增至 GROUP BY 子句,如下所示:
SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, PurchaseOrderNumber;
此查詢會針對每個客戶和每個採購單組合傳回一個數據列,以及該組合的訂單計數。