📦 Step 9: GROUP BYでグループ化
カテゴリ別や月別に集計しよう!
- GROUP BYとは何か、なぜ必要か
- カテゴリ別、都道府県別などの集計方法
- HAVINGでグループに条件指定
- WHEREとHAVINGの違い
- 複数列でのグループ化
- DISTINCTで重複を除外
🎯 1. GROUP BYとは?
1-1. なぜGROUP BYが必要なのか
前のStep 8では、データ全体の集計(全商品の平均価格など)を学びました。
でも実際の仕事では、「カテゴリごとの平均価格」や「月ごとの売上」のように、グループに分けて集計したいことが多いです。
- 「カテゴリごとの商品数と平均価格は?」
- 「都道府県ごとの顧客数は?」
- 「月ごとの売上合計は?」
- 「担当者ごとの成約件数は?」
- 「年齢層ごとの購入傾向は?」
このような「〇〇ごとの集計」をするのがGROUP BY(グループ バイ)です。
1-2. GROUP BYの仕組み
GROUP BYは、データをグループに分けて、それぞれのグループで集計します。
例えば、「カテゴリごとの商品数」を求める場合:
- まず、全データをカテゴリで分類する(果物グループ、野菜グループ、飲料グループ…)
- 次に、各グループの件数を数える
- 最後に、グループごとの結果を1行ずつ表示する
1-3. GROUP BYの基本構文
SELECT グループ化する列, 集計関数(列名) FROM テーブル名 GROUP BY グループ化する列;
| 部分 | 意味 |
|---|---|
SELECT グループ化する列 |
グループの名前(カテゴリ名など)を表示 |
集計関数(列名) |
各グループで計算する内容 |
GROUP BY グループ化する列 |
どの列でグループ分けするか指定 |
📊 2. 練習用テーブルの準備
2-1. テーブルを作成する
今回は「商品」テーブルと「注文」テーブルの2つを使います。
ステップ1:商品テーブルを作成
※横にスクロールできます
ステップ2:商品データを追加
※横にスクロールできます
ステップ3:注文テーブルを作成
※横にスクロールできます
ステップ4:注文データを追加
※横にスクロールできます
2-2. 作成したテーブルの内容
| 商品ID | 商品名 | 価格 | カテゴリ | 在庫数 |
|---|---|---|---|---|
| 1 | りんご | 150 | 果物 | 30 |
| 2 | みかん | 100 | 果物 | 50 |
| 3 | バナナ | 120 | 果物 | 40 |
| 4 | ぶどう | 300 | 果物 | 20 |
| 5 | トマト | 200 | 野菜 | 25 |
| 6 | きゅうり | 80 | 野菜 | 35 |
| 7 | にんじん | 90 | 野菜 | 45 |
| 8 | オレンジジュース | 160 | 飲料 | 20 |
| 9 | りんごジュース | 180 | 飲料 | 15 |
| 10 | お茶 | 120 | 飲料 | 60 |
| 11 | コーヒー | 200 | 飲料 | 30 |
| 12 | チョコレート | 250 | お菓子 | 45 |
カテゴリは「果物」「野菜」「飲料」「お菓子」の4種類です。
| 注文ID | 顧客名 | 都道府県 | 金額 | 注文日 |
|---|---|---|---|---|
| 1 | 田中太郎 | 東京都 | 1500 | 2024-11-01 |
| 2 | 山田花子 | 大阪府 | 2300 | 2024-11-03 |
| 3 | 佐藤次郎 | 東京都 | 800 | 2024-11-05 |
| 4 | 田中太郎 | 東京都 | 3200 | 2024-11-10 |
| 5 | 鈴木一郎 | 神奈川県 | 1200 | 2024-11-12 |
| 6 | 山田花子 | 大阪府 | 4500 | 2024-11-15 |
| 7 | 高橋美咲 | 福岡県 | 900 | 2024-11-18 |
| 8 | 佐藤次郎 | 東京都 | 2800 | 2024-11-20 |
| 9 | 伊藤健太 | 大阪府 | 1800 | 2024-11-22 |
| 10 | 渡辺明 | 神奈川県 | 2500 | 2024-11-25 |
都道府県は「東京都」「大阪府」「神奈川県」「福岡県」の4種類です。
📊 3. 基本的なGROUP BY
3-1. カテゴリごとの商品数を数える
商品をカテゴリごとに分けて、それぞれ何種類あるか数えてみましょう。
※横にスクロールできます
| 部分 | 意味 | なぜ必要? |
|---|---|---|
SELECT カテゴリ |
カテゴリ名を表示 | どのグループの結果か分かるようにするため |
COUNT(*) AS 商品数 |
各グループの件数を数える | グループごとの商品数を知りたいから |
FROM 商品 |
商品テーブルから | データの取得元を指定 |
GROUP BY カテゴリ |
カテゴリでグループ分け | 同じカテゴリをまとめるため |
| カテゴリ | 商品数 |
|---|---|
| 果物 | 4 |
| 野菜 | 3 |
| 飲料 | 4 |
| お菓子 | 1 |
果物は4種類、野菜は3種類、飲料は4種類、お菓子は1種類あることが分かりました!
3-2. カテゴリごとの平均価格を計算する
※横にスクロールできます
| カテゴリ | 平均価格 |
|---|---|
| 果物 | 168 |
| 野菜 | 123 |
| 飲料 | 165 |
| お菓子 | 250 |
お菓子の平均価格が最も高く、野菜が最も安いことが分かります。
3-3. 複数の集計を同時に行う
1つのクエリで、商品数・価格合計・平均価格・最高価格・最低価格を同時に表示できます。
※横にスクロールできます
| カテゴリ | 商品数 | 価格合計 | 平均価格 | 最高価格 | 最低価格 |
|---|---|---|---|---|---|
| 果物 | 4 | 670 | 168 | 300 | 100 |
| 野菜 | 3 | 370 | 123 | 200 | 80 |
| 飲料 | 4 | 660 | 165 | 200 | 120 |
| お菓子 | 1 | 250 | 250 | 250 | 250 |
SELECT句に書ける列は、以下の2種類だけです:
- GROUP BYで指定した列(例:カテゴリ)
- 集計関数(例:COUNT(*)、SUM(価格)など)
これ以外の列をSELECTに書くとエラーになります。
🔍 4. WHEREとGROUP BYの組み合わせ
4-1. 先に絞り込んでから集計する
WHERE句を使って、集計する前にデータを絞り込むことができます。
例えば、「価格が150円以上の商品だけを対象に、カテゴリごとの商品数を調べたい」という場合:
※横にスクロールできます
- FROM:商品テーブルからデータを取得
- WHERE:価格 >= 150 のデータだけに絞り込む
- GROUP BY:絞り込んだデータをカテゴリでグループ化
- SELECT:カテゴリと件数を表示
| カテゴリ | 商品数 |
|---|---|
| 果物 | 2 |
| 野菜 | 1 |
| 飲料 | 3 |
| お菓子 | 1 |
150円以上の商品だけを対象にした結果です。果物は4種類ありましたが、150円以上は2種類(りんご、ぶどう)だけです。
4-2. 都道府県ごとの売上集計
注文テーブルを使って、都道府県ごとの注文件数と売上合計を調べてみましょう。
※横にスクロールできます
| 都道府県 | 注文件数 | 売上合計 |
|---|---|---|
| 東京都 | 4 | 8300 |
| 大阪府 | 3 | 8600 |
| 神奈川県 | 2 | 3700 |
| 福岡県 | 1 | 900 |
大阪府は注文件数は3件ですが、売上合計は最も多いです。
🎯 5. HAVING – グループに条件をつける
5-1. HAVINGとは?
WHERE句は集計「前」のデータに条件をつけますが、HAVING句は集計「後」のグループに条件をつけます。
| 句 | タイミング | 対象 | 例 |
|---|---|---|---|
| WHERE | グループ化の前 | 個々の行 | 価格 >= 150 |
| HAVING | グループ化の後 | グループ | COUNT(*) >= 3 |
例えば、「商品数が3種類以上のカテゴリだけを表示したい」という場合を考えます。
これは「グループ化した後の件数」に条件をつけているので、HAVINGを使います。
5-2. HAVINGの基本構文
SELECT グループ化する列, 集計関数(列名) FROM テーブル名 GROUP BY グループ化する列 HAVING 集計関数(列名) 条件;
5-3. 商品数が3種類以上のカテゴリだけ表示
※横にスクロールできます
- FROM:商品テーブルからデータを取得
- GROUP BY:カテゴリでグループ化
- 集計:各グループのCOUNT(*)を計算
- HAVING:COUNT(*) >= 3 のグループだけを残す
- SELECT:結果を表示
| カテゴリ | 商品数 |
|---|---|
| 果物 | 4 |
| 野菜 | 3 |
| 飲料 | 4 |
「お菓子」は1種類しかないので、条件(3種類以上)に合わないため表示されません。
5-4. 平均価格が150円以上のカテゴリ
※横にスクロールできます
| カテゴリ | 商品数 | 平均価格 |
|---|---|---|
| 果物 | 4 | 168 |
| 飲料 | 4 | 165 |
| お菓子 | 1 | 250 |
野菜の平均価格は123円なので、150円以上という条件に合わないため表示されません。
5-5. WHEREとHAVINGを両方使う
WHERE句とHAVING句は同時に使うことができます。
例:「200円未満の商品だけを対象に、カテゴリごとの商品数を集計し、2種類以上のカテゴリだけ表示」
※横にスクロールできます
- FROM:商品テーブルからデータを取得
- WHERE:価格 < 200 の商品だけに絞り込み(7件)
- GROUP BY:カテゴリでグループ化
- 集計:COUNT(*)とAVG(価格)を計算
- HAVING:COUNT(*) >= 2 のグループだけを残す
- SELECT:結果を表示
| カテゴリ | 商品数 | 平均価格 |
|---|---|---|
| 果物 | 3 | 123 |
| 野菜 | 3 | 123 |
| 飲料 | 2 | 140 |
200円未満の商品だけを対象にしたので、果物は3種類(ぶどう300円は除外)、飲料は2種類(コーヒー200円は除外)になりました。お菓子は0種類(チョコレート250円は除外)なので表示されません。
| 条件の内容 | 使う句 | 例 |
|---|---|---|
| 個々の行の値 | WHERE | 価格 >= 150 |
| 集計関数の結果 | HAVING | COUNT(*) >= 3 |
覚え方:集計関数を条件に使いたい → HAVING、それ以外 → WHERE
📦 6. 複数列でのグループ化
6-1. なぜ複数列でグループ化するのか
GROUP BYには、複数の列を指定することができます。これにより、より細かい分類での集計ができます。
- 「都道府県ごと、さらに顧客ごとの売上」
- 「年ごと、さらに月ごとの売上」
- 「カテゴリごと、さらに価格帯ごとの商品数」
6-2. 都道府県 × 顧客名でグループ化
※横にスクロールできます
GROUP BY 都道府県, 顧客名– 「都道府県」と「顧客名」の組み合わせでグループ化- 例:「東京都・田中太郎」と「東京都・佐藤次郎」は別のグループになる
| 都道府県 | 顧客名 | 注文件数 | 売上合計 |
|---|---|---|---|
| 東京都 | 田中太郎 | 2 | 4700 |
| 東京都 | 佐藤次郎 | 2 | 3600 |
| 大阪府 | 山田花子 | 2 | 6800 |
| 大阪府 | 伊藤健太 | 1 | 1800 |
| 神奈川県 | 鈴木一郎 | 1 | 1200 |
| 神奈川県 | 渡辺明 | 1 | 2500 |
| 福岡県 | 高橋美咲 | 1 | 900 |
山田花子さん(大阪府)が最も売上合計が高いです。
6-3. ORDER BYと組み合わせて見やすくする
複数列でグループ化した結果は、ORDER BYで並び替えると見やすくなります。
※横にスクロールできます
| 都道府県 | 顧客名 | 注文件数 | 売上合計 |
|---|---|---|---|
| 神奈川県 | 渡辺明 | 1 | 2500 |
| 神奈川県 | 鈴木一郎 | 1 | 1200 |
| 大阪府 | 山田花子 | 2 | 6800 |
| 大阪府 | 伊藤健太 | 1 | 1800 |
| 東京都 | 田中太郎 | 2 | 4700 |
| 東京都 | 佐藤次郎 | 2 | 3600 |
| 福岡県 | 高橋美咲 | 1 | 900 |
都道府県ごとに、売上合計が多い順に並んでいます。
✨ 7. DISTINCT – 重複を除外
7-1. DISTINCTとは?
DISTINCT(ディスティンクト)は、重複を除外して、ユニークな値だけを取得する機能です。
英語で「distinct」は「異なる、別々の」という意味です。
SELECT DISTINCT 列名 FROM テーブル名;
7-2. DISTINCTなしとありの比較
DISTINCTなし(重複あり):
※横にスクロールできます
| カテゴリ |
|---|
| 果物 |
| 果物 |
| 果物 |
| 果物 |
| 野菜 |
| 野菜 |
| 野菜 |
| 飲料 |
| 飲料 |
| 飲料 |
| 飲料 |
| お菓子 |
商品の数だけ行が表示され、同じカテゴリが何度も出てきます。
DISTINCTあり(重複なし):
※横にスクロールできます
| カテゴリ |
|---|
| 果物 |
| 野菜 |
| 飲料 |
| お菓子 |
重複が除外され、ユニークな4種類だけが表示されます。
7-3. DISTINCTの活用例
例1:注文があった都道府県の一覧
※横にスクロールできます
| 都道府県 |
|---|
| 神奈川県 |
| 大阪府 |
| 東京都 |
| 福岡県 |
例2:注文した顧客の一覧
※横にスクロールできます
| 顧客名 |
|---|
| 伊藤健太 |
| 佐藤次郎 |
| 山田花子 |
| 田中太郎 |
| 鈴木一郎 |
| 高橋美咲 |
| 渡辺明 |
田中太郎さんと佐藤次郎さんは2回ずつ注文していますが、DISTINCTで重複が除外されています。
7-4. COUNT(DISTINCT 列名) – ユニークな値の数を数える
COUNT()の中でDISTINCTを使うと、ユニークな値の数を数えられます。
※横にスクロールできます
| 顧客数 |
|---|
| 7 |
注文した顧客は7人です(重複を除いた人数)。
比較のため、DISTINCTなしでCOUNTすると:
※横にスクロールできます
| 注文件数 |
|---|
| 10 |
注文件数は10件です(同じ顧客の複数注文も含む)。
| 機能 | 用途 | 集計関数 |
|---|---|---|
| DISTINCT | 重複を除いて一覧表示 | 使えない |
| GROUP BY | グループ化して集計 | 使える |
使い分け:単に一覧を見たい → DISTINCT、集計したい → GROUP BY
📈 8. ORDER BYと組み合わせる
8-1. 集計結果を並び替える
GROUP BYの結果は、ORDER BYで並び替えることができます。
例1:売上合計が多い順にランキング
※横にスクロールできます
| 都道府県 | 注文件数 | 売上合計 |
|---|---|---|
| 大阪府 | 3 | 8600 |
| 東京都 | 4 | 8300 |
| 神奈川県 | 2 | 3700 |
| 福岡県 | 1 | 900 |
売上合計ランキングでは大阪府が1位です。
8-2. LIMITと組み合わせてトップNを取得
例2:売上トップ3の都道府県
※横にスクロールできます
| 都道府県 | 売上合計 |
|---|---|
| 大阪府 | 8600 |
| 東京都 | 8300 |
| 神奈川県 | 3700 |
8-3. SQLの書き順と実行順序
| 書き順 | 句 | 実行順 | 説明 |
|---|---|---|---|
| 1 | SELECT | 5 | 表示する列を選択 |
| 2 | FROM | 1 | テーブルを指定 |
| 3 | WHERE | 2 | 行を絞り込み |
| 4 | GROUP BY | 3 | グループ化 |
| 5 | HAVING | 4 | グループを絞り込み |
| 6 | ORDER BY | 6 | 並び替え |
| 7 | LIMIT | 7 | 件数を制限 |
ポイント:書く順番と実行される順番は違います。特にWHEREとHAVINGの順番に注意!
📝 Step 9 のまとめ
| 機能 | 書き方 | 用途 |
|---|---|---|
| GROUP BY | GROUP BY 列名 |
データをグループ化して集計 |
| HAVING | HAVING 集計関数 条件 |
グループに条件をつける |
| WHERE + GROUP BY | WHERE 条件 GROUP BY 列名 |
先に絞り込んでから集計 |
| 複数列GROUP BY | GROUP BY 列1, 列2 |
より細かい分類で集計 |
| DISTINCT | SELECT DISTINCT 列名 |
重複を除いて一覧表示 |
| COUNT(DISTINCT) | COUNT(DISTINCT 列名) |
ユニークな値の数を数える |
| 条件の内容 | 使う句 | 例 |
|---|---|---|
| 個々の行の値 | WHERE | 価格 >= 150、カテゴリ = ‘果物’ |
| 集計関数の結果 | HAVING | COUNT(*) >= 3、AVG(価格) >= 200 |
GROUP BYでグループ別の集計ができるようになりました!
次のStep 10では、テーブルの結合(JOIN)を学びます。複数のテーブルを組み合わせて、より高度なデータ分析ができるようになります。
📝 練習問題
GROUP BYとHAVINGを使いこなせるように練習しましょう!
カテゴリごとの商品数
商品テーブルから、カテゴリごとの商品数を表示してください。
※横にスクロールできます
解説:GROUP BY カテゴリでカテゴリごとにグループ化し、COUNT(*)で各グループの件数を数えます。
カテゴリごとの平均価格
商品テーブルから、カテゴリごとの平均価格を計算してください。整数に丸めて表示してください。
※横にスクロールできます
解説:AVG()で平均を計算し、ROUND()で整数に丸めます。
都道府県ごとの注文件数
注文テーブルから、都道府県ごとの注文件数を表示してください。
※横にスクロールできます
解説:都道府県でグループ化して、各都道府県の注文件数を数えます。
カテゴリの一覧
商品テーブルから、重複を除いて全てのカテゴリを一覧表示してください。
※横にスクロールできます
解説:DISTINCTで重複を除外します。集計が不要な場合はGROUP BYより簡潔です。
カテゴリごとの詳細統計
商品テーブルから、カテゴリごとに商品数、価格合計、平均価格、最高価格、最低価格を表示してください。
※横にスクロールできます
解説:複数の集計関数を同時に使って、詳細な統計を取得します。
商品数が多いカテゴリ
商品テーブルから、商品数が3種類以上のカテゴリだけを表示してください。
※横にスクロールできます
解説:HAVING句で、集計結果(商品数)に条件をつけています。WHEREではなくHAVINGを使う点がポイントです。
高額商品のカテゴリ別集計
商品テーブルから、価格が150円以上の商品だけを対象に、カテゴリごとの商品数と平均価格を表示してください。
※横にスクロールできます
解説:WHERE句で先に絞り込んでから、GROUP BYでグループ化します。
売上ランキング
注文テーブルから、都道府県ごとの売上合計を計算し、売上が多い順に表示してください。
※横にスクロールできます
解説:GROUP BYで集計してから、ORDER BY DESC で降順に並び替えます。
WHEREとHAVINGの組み合わせ
商品テーブルから、価格が200円未満の商品だけを対象に、カテゴリごとの商品数と平均価格を表示してください。ただし、商品数が2種類以上のカテゴリだけを表示してください。
※横にスクロールできます
解説:WHERE(行の絞り込み)→ GROUP BY(グループ化)→ HAVING(グループの絞り込み)の順で処理されます。
売上トップ3
注文テーブルから、都道府県ごとの注文件数と売上合計を計算し、売上が多い上位3都道府県だけを表示してください。
※横にスクロールできます
解説:GROUP BYで集計し、ORDER BYで並び替え、LIMITで上位3件だけを取得します。
ユニークな顧客数
注文テーブルから、注文した顧客は全部で何人いるか(重複を除いて)調べてください。
※横にスクロールできます
解説:COUNT()の中でDISTINCTを使って、重複を除いた件数を数えます。結果は7人です。
複数列でのグループ化
注文テーブルから、都道府県と顧客名の組み合わせごとに、注文件数と売上合計を表示してください。売上合計が多い順に並べてください。
※横にスクロールできます
解説:複数の列でグループ化すると、より細かい分類での集計ができます。
平均価格が高いカテゴリ
商品テーブルから、カテゴリごとの商品数と平均価格を表示してください。ただし、平均価格が160円以上のカテゴリだけを、平均価格の高い順に表示してください。
※横にスクロールできます
解説:HAVINGで集計結果に条件をつけ、ORDER BYで並び替えます。
❓ よくある質問
Q1: GROUP BYを使わないとエラーになるのはなぜですか?
SELECT句に集計関数と通常の列が混在している場合、通常の列は必ずGROUP BYに含める必要があります。
例えば、SELECT カテゴリ, COUNT(*)と書いたら、GROUP BY カテゴリが必須です。これは「どの行のカテゴリを表示するか」を決めるためです。
Q2: WHEREとHAVINGはどう使い分けますか?
シンプルな覚え方:集計関数を条件に使いたい → HAVING、それ以外 → WHERE
- WHERE:個々の行に条件(例:価格 >= 150)
- HAVING:グループに条件(例:COUNT(*) >= 3)
Q3: DISTINCTとGROUP BYはどう違いますか?
DISTINCT:重複を除いて表示するだけ
GROUP BY:グループ化して集計関数が使える
単に一覧を見たいだけならDISTINCT、集計したい場合はGROUP BYを使います。
Q4: GROUP BYの順番は結果に影響しますか?
いいえ、結果は同じです。GROUP BY 都道府県, 顧客名とGROUP BY 顧客名, 都道府県は同じグループを作ります。
ただし、ORDER BYで明示的に並び替えないと、表示順は不定です。
Q5: NULLはグループ化でどう扱われますか?
NULL値は1つのグループとして扱われます。例えば、カテゴリがNULLの行は全て同じグループになります。
Q6: HAVINGでASで付けた名前は使えますか?
SQLiteでは使えますが、他のデータベース(MySQLの一部、PostgreSQLなど)では使えないことがあります。
安全のため、HAVINGでは集計関数をそのまま書く(例:HAVING COUNT(*) >= 3)のがおすすめです。
学習メモ
SQL基礎 - Step 9