SQLのGROUP BYは、データを特定のカテゴリごとにまとめ、集計を行うための句です。これは、特定のカテゴリや属性ごとにデータの合計、平均、最大値、最小値などを計算したい場合に非常に役立ちます。
基本的な使い方
GROUP BYの最も基本的な使い方は、SELECT文で集計関数(COUNT(), SUM(), AVG(), MAX(), MIN()など)と一緒に使用することです。
構文:
SELECT
グループ化したいカラム,
集計関数(集計したいカラム)
FROM
テーブル名
GROUP BY
グループ化したいカラム;
例:
例えば、salesテーブルに商品ごとの売上データがある場合を考えます。
| product_id | sales_date | quantity | price |
|---|---|---|---|
| 101 | 2025-09-01 | 5 | 1000 |
| 102 | 2025-09-01 | 2 | 2500 |
| 101 | 2025-09-02 | 3 | 1000 |
| 103 | 2025-09-02 | 1 | 5000 |
このテーブルから、商品ごとの合計売上額を計算したい場合は、GROUP BY product_idと指定します。
SELECT
product_id,
SUM(quantity * price) AS total_sales
FROM
sales
GROUP BY
product_id;
このクエリを実行すると、product_idごとにquantity * priceの合計が計算され、以下の結果が得られます。
| product_id | total_sales |
|---|---|
| 101 | 8000 |
| 102 | 5000 |
| 103 | 5000 |
間違えやすいポイントと解決策
GROUP BYを使う上で、初心者がつまずきやすいポイントがいくつかあります。
間違えやすいポイント①: SELECT句とGROUP BY句のカラム不一致
SELECT句に書かれた、集計関数ではないカラムは、すべてGROUP BY句にも書く必要があります。
❌ 悪い例:
SELECT
product_id,
sales_date, -- 集計関数ではない
SUM(quantity)
FROM
sales
GROUP BY
product_id; -- sales_dateが抜けている
このクエリは、sales_dateがどのグループに属するかわからないため、エラーになります。
➡ 解決策:
SELECT句にsales_dateを含めたければ、GROUP BY句にもsales_dateを追加して、より細かくグループ化します。
SELECT
product_id,
sales_date,
SUM(quantity)
FROM
sales
GROUP BY
product_id, sales_date; -- sales_dateを追加
間違えやすいポイント②: WHERE句で集計結果を絞り込む
GROUP BYの集計結果に対して条件をつけたい場合、WHERE句は使えません。WHERE句は、グループ化前の元のデータに対して条件を適用します。
❌ 悪い例:
SELECT
product_id,
SUM(quantity) AS total_quantity
FROM
sales
WHERE
total_quantity > 100 -- エラー!
GROUP BY
product_id;
このクエリは、total_quantityがGROUP BYの後に計算されるため、WHERE句では参照できず、エラーになります。
➡ 解決策: HAVING句を使う
集計結果に対する条件は、HAVING句を使います。HAVING句はGROUP BYの後に記述します。
SELECT
product_id,
SUM(quantity) AS total_quantity
FROM
sales
GROUP BY
product_id
HAVING
SUM(quantity) > 100; -- HAVING句で集計結果に条件を適用
HAVING句を使うことで、「合計数量が100を超える商品のみ」といった条件で集計結果を絞り込むことができます。
これらのポイントを意識してクエリを書くことで、エラーを減らし、SQLをよりスムーズに使えるようになります。
注意点
GROUP BYを使用する際は、以下の2つのポイントに特に注意することで、より効率的で正確なクエリを作成できます。
1. 名称ではなくIDや数値でGROUP BYする
GROUP BYでグループ化する際、文字列である名称ではなく、IDや数値を使用することが非常に重要です。
パフォーマンスの向上
データベースは、文字列よりもIDや数値の比較をはるかに高速に処理できます。名称でグループ化すると、データベースは各行の文字列データを比較する必要があり、その分処理が遅くなります。IDや数値は固定長のデータなので、比較が高速です。
正確性の確保
名称には表記ゆれや同名の異なるデータが存在するリスクがあります。例えば「Apple」と「apple」のような表記ゆれ、あるいは偶然同じ名前の異なる商品などが存在する場合、意図しない集計結果になる可能性があります。IDや数値は一意に割り当てられるため、こうした問題を確実に防ぎ、正確な集計を行うことができます。
2. LEFT JOINとの組み合わせ
LEFT JOINとGROUP BYを組み合わせる際は、サブクエリを活用することでパフォーマンスを大幅に向上させることができます。
❌ 悪い例: JOINしてからGROUP BYする
SELECT
p.product_name,
SUM(s.quantity * s.price) AS total_sales
FROM
products p
LEFT JOIN
sales s ON p.product_id = s.product_id
GROUP BY
p.product_name;
この方法では、まずテーブルを結合して行数を増やしてからグループ化するため、データ量が増えると処理が遅くなります。
⭕️ 良い例: サブクエリで集計してからJOINする
SELECT
p.product_name,
T1.total_sales
FROM
products p
LEFT JOIN
(
SELECT
product_id,
SUM(quantity * s.price) AS total_sales
FROM
sales s
GROUP BY
product_id
) AS T1 ON p.product_id = T1.product_id;
この方法では、まずsalesテーブルでproduct_id(ID、数値)をキーに集計して行数を減らし、その結果をproductsテーブルと結合します。これにより、結合処理が軽くなり、全体的なパフォーマンスが向上します。
まとめ
GROUP BYは、SQLでカテゴリごとにデータを集計するための機能です。
使い方を正しく理解することで、売上や件数などを効率的に分析できます。
特に注意すべきポイントは以下の4つです。
SELECTに書いたカラムはすべてGROUP BYにも含める- 集計結果に条件をつけるときは
HAVINGを使う - グループ化は文字列ではなくIDや数値で行う(性能・正確性アップ)
- JOINと組み合わせるときはサブクエリで先に集計(パフォーマンス改善)
GROUP BYは他の句や関数とセットで使うことが多いため、最初は何をしているのか分かりにくいものです。そんなときにこのブログが少しでも理解の手助けになれば嬉しいです。