SQL:HAVING
1学習の目的
- HAVING で「集計した後の値」に条件を付けられるようになる。「売上100万円以上のカテゴリだけ」といった抽出ができるようになる。
- WHERE と HAVING の役割の違いを、実行される順番から理解する。この2つを取り違えると、エラーになるか、結果が静かに変わる。
2基礎解説
前章では全グループが表示されました。「件数が3以上のグループだけ」を絞りたい——それが HAVING の役割です。
| WHERE | HAVING | |
|---|---|---|
| 効くタイミング | 集計の前 | 集計の後 |
| 対象 | 1行1行 | グループ |
| 集計関数 | 使えない | 使える |
| 例 | WHERE price > 1000 | HAVING COUNT(*) >= 2 |
- SQLは「WHERE → GROUP BY → HAVING」の順に実行される。WHEREで行を減らし、残った行をグループ化し、そのグループをHAVINGで絞る。
- WHERE に集計関数は書けない。WHERE COUNT(*) > 1 は「misuse of aggregate」というエラーになる。集計はまだ行われていない段階だから。
- 句の順番は SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT。HAVING は GROUP BY の直後。
- HAVING には集計結果の別名も使える環境が多い(HAVING 件数 >= 2)。ただし標準SQLでは HAVING COUNT(*) >= 2 と書くほうが確実。
- どちらでも書ける条件は WHERE に書く。先に行を減らしたほうが処理が速く、意図も明確になる。
現場使用例:注文が3件以上の顧客、売上100万円以上の店舗、平均点60点未満のクラス、在庫が1つもない仕入先。「◯件以上」「合計◯円以上」という条件はすべてHAVING。
-- 商品が2件以上あるカテゴリだけ SELECT category, COUNT(*) AS 件数 FROM products GROUP BY category HAVING COUNT(*) >= 2; -- → PC(2) と 周辺機器(4)。未分類(1)は除外される -- 合計金額が2万円を超えるカテゴリ SELECT category, SUM(price) AS 合計 FROM products GROUP BY category HAVING SUM(price) > 20000; -- ❌ WHERE には集計関数を書けない SELECT category FROM products WHERE COUNT(*) > 1 GROUP BY category; -- → misuse of aggregate: COUNT() というエラー -- WHERE と HAVING を両方使う SELECT category, COUNT(*) AS 件数 FROM products WHERE price IS NOT NULL -- ① 行を絞る GROUP BY category -- ② グループ化 HAVING COUNT(*) >= 2 -- ③ グループを絞る ORDER BY 件数 DESC; -- ④ 並べる
3基本ドリル(10問)
2行。PC 2 / 周辺機器 4
GROUP BY の後ろに HAVING COUNT(*) >= 2 を付ける。
SELECT category, COUNT(*) AS 件数 FROM products GROUP BY category HAVING COUNT(*) >= 2;
未分類(1件)が除外された。前章では全グループが表示されたが、HAVINGで条件に合うグループだけに絞れる。
A. 正しく動く B. エラーになる C. 0件になる D. 全件返る 選択★☆☆無料
解答 == B
WHEREが効くのは集計の前か後か。
B
「misuse of aggregate」というエラーになる。WHEREが効く時点ではまだ集計されていないので、COUNT の結果は存在しない。
2行。NULL 25000 / PC 173000
HAVING SUM(price) > 20000 と書く。
SELECT category, SUM(price) AS 合計 FROM products GROUP BY category HAVING SUM(price) > 20000;
周辺機器(13200円)が除外された。件数は4件で最多だが、合計金額では条件を満たさない。
SELECT category, AVG(price) AS 平均 FROM products GROUP BY category ____ AVG(price) > 10000;
2行。NULL 25000.0 / PC 86500.0
集計後の条件を指定するキーワード。6文字。
HAVING
HAVING は GROUP BY の直後に書く。ORDER BY があるなら、その前になる。
A. GROUP BY → WHERE → HAVING B. WHERE → GROUP BY → HAVING C. HAVING → GROUP BY → WHERE D. WHERE → HAVING → GROUP BY 選択★☆☆無料
解答 == B
行を絞る → まとめる → グループを絞る。
B
この順番が実行される順番でもある。WHEREで行を減らし、GROUP BYでまとめ、HAVINGでグループを絞る。順番を変えるとエラーになる。
1行。周辺機器 4
HAVING COUNT(*) >= 3 と書く。
SELECT category, COUNT(*) AS 件数 FROM products GROUP BY category HAVING COUNT(*) >= 3;
条件を厳しくするとグループが減る。2件以上なら2グループ、3件以上なら1グループになる。
SELECT category, COUNT(*) AS 件数 FROM products GROUP BY category HAVING COUNT(*) >= 2 ____ 件数 DESC;
2行。周辺機器 4 / PC 2
並べ替えを指示する2語。HAVING の後ろに書く。
ORDER BY
HAVING の後ろが ORDER BY。句の順番は SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT。
A. WHERE B. HAVING C. どちらでもよい D. 両方に書く 選択★★☆無料
解答 == A
これは1行ごとに判定できる条件か、集計後の値か。
A
集計関数を使わない条件は WHERE に書く。先に行を減らしたほうが処理が速く、意図も明確になる。
2行。PC 2 / 周辺機器 3
WHERE price IS NOT NULL で行を絞り、GROUP BY してから HAVING で絞る。
SELECT category, COUNT(*) AS 件数 FROM products WHERE price IS NOT NULL GROUP BY category HAVING COUNT(*) >= 2;
WHERE と HAVING は併用できる。周辺機器が4件から3件になったのは、WHEREで価格未入力の1件が先に除かれたため。
1行。PC 2 173000
HAVING の中で AND を使って2つの条件をつなぐ。
SELECT category, COUNT(*) AS 件数, SUM(price) AS 合計 FROM products GROUP BY category HAVING COUNT(*) >= 2 AND SUM(price) > 20000;
HAVING でも AND / OR が使える。周辺機器は件数4で1つ目は満たすが、合計13200円で2つ目を満たさないため除外される。
4実践シナリオ(5問)
2行。PC 2 173000 / 周辺機器 4 13200
COALESCE で分類名を作り、GROUP BY し、HAVING COUNT(*) >= 2 で絞り、ORDER BY で並べる。
SELECT COALESCE(category, '未分類') AS 分類, COUNT(*) AS 商品数, SUM(price) AS 合計 FROM products GROUP BY 分類 HAVING COUNT(*) >= 2 ORDER BY 合計 DESC;
4つの句がすべて揃った形。GROUP BY → HAVING → ORDER BY の流れは、実務のレポートSQLの標準構成になる。
2行。NULL 25000.0 / PC 86500.0
HAVING AVG(price) > 10000。表示は ROUND(AVG(price), 1)。
SELECT category, ROUND(AVG(price), 1) AS 平均単価 FROM products GROUP BY category HAVING AVG(price) > 10000;
SELECT で ROUND しても、HAVING の条件には影響しない。表示の丸めと、判定に使う値は別物として扱われる。
2行。PC 955000 / 周辺機器 467400
SUM(COALESCE(price,0) * COALESCE(stock,0)) を HAVING でも使う。
SELECT category, SUM(COALESCE(price, 0) * COALESCE(stock, 0)) AS 在庫額 FROM products GROUP BY category HAVING SUM(COALESCE(price, 0) * COALESCE(stock, 0)) >= 400000 ORDER BY 在庫額 DESC;
HAVING には SELECT と同じ式を書くのが確実。長くなるが、環境によっては別名が使えないため、この形が最も互換性が高い。
2行。PC 2 86500.0 / 周辺機器 3 4400.0
「1000円以上」は1行ごとの条件なので WHERE、「2件以上」は集計後なので HAVING。
SELECT category, COUNT(*) AS 件数, ROUND(AVG(price), 1) AS 平均 FROM products WHERE price >= 1000 GROUP BY category HAVING COUNT(*) >= 2;
条件を2つの句に振り分ける判断がこの問題の要点。行の条件はWHERE、グループの条件はHAVING——迷ったら「集計関数を使うか」で決める。
1行。未分類 1
HAVING COUNT(*) = 1 と書く。「以上」ではなく「ちょうど」なので = を使う。
SELECT COALESCE(category, '未分類') AS 分類, COUNT(*) AS 件数 FROM products GROUP BY 分類 HAVING COUNT(*) = 1;
「少ないもの」を探すのもHAVINGの仕事。データの偏りや、登録漏れの疑いがあるグループを見つけるときに使う。
5仕上げ課題
選定条件
・対象は価格が入力済みの商品のみ(未入力は集計から除く)
・商品が 2 件以上あるカテゴリ
・かつ、在庫金額の合計が 40万円 以上
表示する列
① 分類(NULLは「未分類」)→ 別名「分類」
② 商品数 → 別名「商品数」
③ 平均単価(小数第1位まで)→ 別名「平均単価」
④ 在庫金額の合計(NULLは0として扱う)→ 別名「在庫額」
並び順:在庫額の大きい順
期待される結果(4列 × 2行)
分類 | 商品数 | 平均単価 | 在庫額
PC | 2 | 86500.0 | 955000
周辺機器 | 3 | 4400.0 | 467400
※ どの条件を WHERE に、どの条件を HAVING に書くべきかを考えながら組み立てること。
4列 × 2行が完全一致
「価格が入力済み」は1行ごとの条件なので WHERE。「2件以上」「40万円以上」は集計後の条件なので HAVING に AND でつなぐ。在庫額は SUM(COALESCE(price,0) * COALESCE(stock,0))。
SELECT COALESCE(category, '未分類') AS 分類, COUNT(*) AS 商品数, ROUND(AVG(price), 1) AS 平均単価, SUM(COALESCE(price, 0) * COALESCE(stock, 0)) AS 在庫額 FROM products WHERE price IS NOT NULL GROUP BY 分類 HAVING COUNT(*) >= 2 AND SUM(COALESCE(price, 0) * COALESCE(stock, 0)) >= 400000 ORDER BY 在庫額 DESC;
WHERE と HAVING を正しく振り分けられたかが、この課題の核心だ。「価格が入力済み」は1行ごとに判定できるのでWHERE、「2件以上」「40万円以上」は集計しないと分からないのでHAVING——この判断ができれば、SQLの構造を理解したことになる。
もし「価格が入力済み」をHAVINGに書こうとすると、そもそも書けない。逆に「2件以上」をWHEREに書くと misuse of aggregate でエラーになる。SQLは書ける場所を制限することで、間違いを防いでいるとも言える。
結果を見ると周辺機器の商品数が3になっている。元は4件だが、WHEREで価格未入力の1件が先に除かれたためだ。もしWHEREを書かなければ4件のまま集計され、平均単価も変わる。どの段階でデータを減らすかが、最終的な数字を左右する。
ここまでで、1つのテーブルからの集計は一通りできるようになった。次章からは複数のテーブルを扱う。商品テーブルと注文テーブルを結び付けられるようになると、SQLの世界が一気に広がる。