青の統計学-DS Playground-

HAVING: 集計結果を条件で絞る

Stage 2 — 第3章 | データ分析基礎カリキュラム 推定学習時間:30〜40分 | 難易度:★★★☆☆


この章で学ぶこと

前章では、GROUP BY を使ってカテゴリ別・顧客別に集計する方法を学びました。 集計表を作ると、次に「集計結果が一定以上のものだけ見たい」という場面が出てきます。

たとえば、ECサイトでは次のような問いがあります。

  • 注文回数が3回以上の顧客だけを見たい
  • 売上が10万円以上の商品カテゴリだけを抽出したい
  • 平均注文金額が高い地域だけを確認したい

このように、集計した後の結果を絞るときに使うのが HAVING です。

この章を終えると、こんなことができるようになります:

  • WHEREHAVING の違いを説明できる
  • 集計後の件数や合計金額で結果を絞れる
  • GROUP BYHAVING を組み合わせたSQLを書ける
  • 実務で「注目すべきグループ」を抽出できる

1. WHEREは集計前、HAVINGは集計後

WHEREHAVING はどちらも条件で絞るために使います。 ただし、絞るタイミングが違います。

絞る対象
WHERE 集計前の行 完了注文だけに絞る
HAVING 集計後のグループ 注文回数が3回以上の顧客だけに絞る

顧客ごとの注文件数を出すSQLを考えます。

SELECT
            customer_id,
            COUNT(*) AS order_count
          FROM orders
          WHERE status = 'completed'
          GROUP BY customer_id;
          

ここで WHERE status = 'completed' は、集計前に完了注文だけを残しています。 その後、customer_id ごとに集計します。


2. HAVINGで集計結果を絞る

完了注文が3回以上ある顧客だけを見たい場合は、HAVING を使います。

SELECT
            customer_id,
            COUNT(*) AS order_count
          FROM orders
          WHERE status = 'completed'
          GROUP BY customer_id
          HAVING COUNT(*) >= 3;
          

このSQLの流れは次の通りです。

  1. orders からデータを読む
  2. WHERE で完了注文だけに絞る
  3. GROUP BY customer_id で顧客ごとにまとめる
  4. HAVING COUNT(*) >= 3 で注文回数3回以上の顧客だけ残す

HAVING は、COUNT(*)SUM(...) のような集計結果に対する条件を書く場所です。


3. 売上が大きいカテゴリだけを見る

商品カテゴリ別の売上を出し、売上が10万円以上のカテゴリだけを残す例です。

SELECT
            p.category,
            SUM(oi.quantity * oi.unit_price) AS sales
          FROM order_items AS oi
          JOIN products AS p
            ON oi.product_id = p.product_id
          GROUP BY p.category
          HAVING SUM(oi.quantity * oi.unit_price) >= 100000
          ORDER BY sales DESC;
          

このSQLは、全カテゴリを集計したあと、売上が10万円以上のカテゴリだけを表示します。

実務では、すべてのカテゴリを並べるより、一定規模以上のカテゴリに絞ったほうが意思決定しやすいことがあります。 ただし、小さいカテゴリを見落としてよいかは、分析目的によって変わります。


4. 平均値で絞る

HAVING では、平均値も条件にできます。

SELECT
            c.prefecture,
            AVG(o.total_amount) AS average_order_amount,
            COUNT(*) AS order_count
          FROM orders AS o
          JOIN customers AS c
            ON o.customer_id = c.customer_id
          WHERE o.status = 'completed'
          GROUP BY c.prefecture
          HAVING AVG(o.total_amount) >= 8000
          ORDER BY average_order_amount DESC;
          

これは、完了注文の平均注文金額が8,000円以上の都道府県を抽出します。

平均値で絞るときは、件数も一緒に見るのが大切です。 注文が1件しかない地域の平均は、たまたま高く見えることがあります。 そのため、このSQLでは COUNT(*) AS order_count も表示しています。


5. 複数のHAVING条件を書く

集計後の条件を複数組み合わせることもできます。

SELECT
            customer_id,
            COUNT(*) AS order_count,
            SUM(total_amount) AS total_sales
          FROM orders
          WHERE status = 'completed'
          GROUP BY customer_id
          HAVING COUNT(*) >= 3
             AND SUM(total_amount) >= 30000
          ORDER BY total_sales DESC;
          

これは、完了注文が3回以上あり、累計購入金額が3万円以上の顧客を抽出します。

このような条件は、優良顧客候補の抽出やキャンペーン対象者の選定に使えます。 ただし、条件の基準は業務目的に合わせて決める必要があります。


6. WHEREに集計関数は書かない

初学者がよく迷うのが、次のような書き方です。

SELECT
            customer_id,
            COUNT(*) AS order_count
          FROM orders
          WHERE COUNT(*) >= 3
          GROUP BY customer_id;
          

これは適切ではありません。 WHERE は集計前の行を絞る句なので、COUNT(*) のような集計結果はまだ存在していないからです。

集計結果で絞る場合は、次のように HAVING を使います。

SELECT
            customer_id,
            COUNT(*) AS order_count
          FROM orders
          GROUP BY customer_id
          HAVING COUNT(*) >= 3;
          

WHEREHAVING の役割を分けて考えましょう。


7. HAVINGを使う前に全体も確認する

HAVING で条件を絞ると、注目したいグループだけを見られます。 一方で、条件に満たないグループが見えなくなります。

そのため、実務では次の順番で確認すると安全です。

  1. まず全カテゴリ・全顧客の集計表を見る
  2. 件数や売上の分布を確認する
  3. 目的に合う基準で HAVING を追加する
  4. 除外されたグループが問題ないか確認する

SQLは結果を絞るほど見やすくなりますが、同時に見えない範囲も増えます。 条件を入れた理由を説明できることが大切です。


実務での使いどころ: 注目すべきグループだけを見る

HAVINGは、集計した後のグループを絞るために使います。 たとえば、全カテゴリを並べるだけでなく、売上が一定以上あるカテゴリだけを見たい場合に使います。

SELECT
            p.category,
            SUM(oi.quantity * oi.unit_price) AS sales
          FROM order_items AS oi
          JOIN products AS p
            ON oi.product_id = p.product_id
          GROUP BY p.category
          HAVING SUM(oi.quantity * oi.unit_price) >= 100000
          ORDER BY sales DESC;
          

このSQLは、売上が10万円以上のカテゴリだけを残します。 WHEREは行を絞り、HAVINGは集計後のグループを絞ります。 この違いを間違えると、分析対象が変わります。

やりたいこと 使う句
完了注文だけにする WHERE
2026年5月だけにする WHERE
売上10万円以上のカテゴリだけにする HAVING
注文件数10件以上の顧客だけにする HAVING

HAVINGは便利ですが、少数のグループだけを見ると全体感を失うことがあります。 HAVINGで絞る前の全体集計も確認しておきましょう。

ミニ演習

次の条件はWHEREとHAVINGのどちらに書くべきか考えてください。

  1. status = 'completed' の注文だけにする。
  2. カテゴリ別売上が100,000円以上のカテゴリだけにする。
  3. 2026年5月の注文だけにする。
  4. 注文件数が3件以上の顧客だけにする。

まとめ

構文 意味
WHERE 集計前の行を絞る WHERE status = 'completed'
HAVING 集計後のグループを絞る HAVING COUNT(*) >= 3
HAVING SUM(...) 合計値で絞る HAVING SUM(total_amount) >= 100000
HAVING AVG(...) 平均値で絞る HAVING AVG(total_amount) >= 8000

この章のキーメッセージ: HAVING は、集計した後の結果を条件で絞るための句です。WHERE は集計前、HAVING は集計後という違いを押さえましょう。


この章の確認

  1. WHEREHAVING の違いを説明してください。
  2. 完了注文が3回以上ある顧客を抽出するSQLを書いてください。
  3. カテゴリ別売上が10万円以上のカテゴリだけを表示するには、どの句を使いますか?
  4. 平均値で絞るとき、件数も一緒に確認したほうがよい理由を説明してください。

関連演習