Query Go
グループに条件を付ける - HAVING の使い方・オプション・サンプル

グループに条件を付ける - HAVING

グループ化後の結果に対する絞り込み。WHERE との違いと使い分けを押さえる

概念図

HAVING diagram

構文

sql
SELECT 列, 集約(...) FROM t GROUP BYHAVING 集約(...) 条件

サンプル

10 名以上の部署だけを抽出する

sql
SELECT department_id, COUNT(*) AS cnt
FROM employees
GROUP BY department_id
HAVING COUNT(*) >= 10;

HAVING とは

HAVINGGROUP BY でまとめた グループ単位の集約結果に対して条件を課す句です。SUM(amount) > 1000COUNT(*) >= 5 のように、集約関数の結果で絞り込みたいときに使います。

WHERE との違い

実行順序は概ね FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY です。

  • WHERE: 集約前の 個々の行 に対する絞り込み。ここで落とせる行は先に落とした方が速い
  • HAVING: 集約後の グループ に対する絞り込み。集約関数が使える唯一の絞り込み節

「アクティブなユーザーの中で」→ WHERE、「購入金額合計が 1 万円超のユーザー」→ HAVING、と分けて考えると迷いません。

sql
-- アクティブユーザーに限定しつつ、合計購入額が10000超のユーザーだけ
SELECT user_id, SUM(amount) AS total
FROM orders
WHERE status = 'active'       -- 行レベルの絞り込み
GROUP BY user_id
HAVING SUM(amount) > 10000;   -- グループレベルの絞り込み

GROUP BY なしの HAVING

GROUP BY を書かずに HAVING だけを書くと、テーブル全体が 1 つのグループとして扱われます。使う場面は少ないですが、「合計が閾値を超えているときだけ 1 行返す」といった監視クエリに使えます。

よくある落とし穴

  • WHERE に集約関数を書いてしまう: WHERE SUM(x) > 100 はエラー。HAVING に書く
  • HAVING にエイリアスが使えない DB: PostgreSQL は SELECT のエイリアスを HAVING で使えないので、式を書き直すか CTE にする必要がある
  • 行レベルの条件を HAVING に書いてしまう: 集約前に落とせる条件は WHERE に書いた方がスキャン量が減り高速

関連トピック