使用 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 取得原始 830 個來源資料列,並根據 CustomerID 值分成 89 個群組。 每個相異的 CustomerID 值在 GROUP BY 查詢中產生一個輸出資料列

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

針對每個 CustomerID 值,查詢彙總並算出資料列數目,因此,結果會顯示 SalesOrderHeader 資料表中有多少資料列屬於每個客戶。

CustomerID

OrderCount

1234

3

1005

1

請注意,GROUP BY 不保證結果的順序。 通常,由於查詢處理器執行群組作業的方式,將會依群組值的順序傳回結果。 不過,請勿依賴此行為。 如果需要排序結果,您必須明確包含 ORDER 子句:

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY CustomerID;

這次會依指定的順序傳回結果:

CustomerID

OrderCount

1005

1

1234

3

SELECT 陳述式中的子句依下列順序套用:

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. 排序依據

在 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 時,通常需要了解為何發生下列類型的錯誤訊息:

訊息 8120,層級 16,狀態 1,行 2。資料行 <column_name> 在 select 清單中無效,因為並未出現在彙總函數或 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;

此查詢會針對每個客戶和每個採購單的組合,各傳回一個資料列,以及該組合的訂單計數。