GROUP BY を使用してデータを集計する
集計関数は分析に役立ちますが、集計する前にデータをサブセットに配置することが必要な場合があります。 このセクションでは、GROUP BY 句を使用してこれを行う方法について説明します。
GROUP BY 句の使用
学習したように、SELECT ステートメントが処理されると、FROM 句と WHERE 句が評価された後に、仮想テーブルが作成されます。 仮想テーブルの内容を追加処理できるようになりました。 GROUP BY 句を使用すると、この仮想テーブルの内容を行のグループに分割できます。
行をグループ化するには、GROUP BY 句で 1 つ以上の要素を指定します。
GROUP BY <value1> [, <value2>, …]
GROUP BY は、句で指定された要素によって決定されたグループを作成し、行を各グループに配置します。
たとえば、次のクエリでは、Sales.SalesOrderHeader テーブル内の CustomerID ごとに 1 行ずつ、グループ化された行のセットが生成されます。 GROUP BY プロセスを見るもう 1 つの方法は、 CustomerID に同じ値を持つすべての行がグループ化され、1 つの結果行に返されることです。
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 クエリで 1 行の出力が生成されます
SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
各 CustomerID 値について、クエリは行を集計してカウントするため、SalesOrderHeader テーブル内の各顧客に属する行の数が表示されます。
顧客ID
注文数
1234
3
1005
1
GROUP BY では結果の順序が保証されないことに注意してください。 多くの場合、クエリ プロセッサによってグループ化操作が実行される方法の結果として、結果はグループ値の順序で返されます。 ただし、この動作に依存しないでください。 結果を並べ替える必要がある場合は、ORDER 句を明示的に含める必要があります。
SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY CustomerID;
今回は、指定した順序で結果が返されます。
顧客ID
注文数
1005
1
1234
3
SELECT ステートメントの句は、次の順序で適用されます。
- FROM
- どこ
- GROUP BY
- HAVING
- SELECT
- ORDER BY
列の別名は 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;
ただし、次のクエリは成功し、顧客 ID で結果をグループ化して並べ替えます。
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> は、集計関数または 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.
もう 1 つの考え方を次に示します。 このクエリは、 CustomerID 値ごとに 1 行を返します。 ただし、同じ CustomerID の行には異なる PurchaseOrderNumber 値を指定できるため、返される値はどれですか?
顧客 ID および発注書ごとの注文を表示する場合は、次のように、GROUP BY 句に PurchaseOrderNumber 列を追加できます。
SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, PurchaseOrderNumber;
このクエリでは、顧客ごとに 1 行、各発注書の組み合わせ、およびその組み合わせの注文数が返されます。