SQL / LESSON 08 / SQL08

SQL:HAVING

1学習の目的

2基礎解説

前章では全グループが表示されました。「件数が3以上のグループだけ」を絞りたい——それが HAVING の役割です。

WHEREHAVING
効くタイミング集計の集計の
対象1行1行グループ
集計関数使えない使える
WHERE price > 1000HAVING COUNT(*) >= 2
✅ 覚えるべき重要ポイント
  1. SQLは「WHERE → GROUP BY → HAVING」の順に実行される。WHEREで行を減らし、残った行をグループ化し、そのグループをHAVINGで絞る。
  2. WHERE に集計関数は書けないWHERE COUNT(*) > 1 は「misuse of aggregate」というエラーになる。集計はまだ行われていない段階だから。
  3. 句の順番は SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMITHAVING は GROUP BY の直後
  4. HAVING には集計結果の別名も使える環境が多い(HAVING 件数 >= 2)。ただし標準SQLでは HAVING COUNT(*) >= 2 と書くほうが確実。
  5. どちらでも書ける条件は 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問)

SQL08-D01 商品が 2件以上あるカテゴリだけを、category と件数(別名「件数」)で取り出すSQLを書け。 コーディング★☆☆無料
期待される結果

2行。PC 2 / 周辺機器 4

ヒント

GROUP BY の後ろに HAVING COUNT(*) >= 2 を付ける。

模範解答
SELECT category, COUNT(*) AS 件数
FROM products
GROUP BY category
HAVING COUNT(*) >= 2;
解説

未分類(1件)が除外された。前章では全グループが表示されたが、HAVINGで条件に合うグループだけに絞れる。

SQL08-D02 WHERE COUNT(*) > 1 と書くとどうなるか。
A. 正しく動く B. エラーになる C. 0件になる D. 全件返る
選択★☆☆無料
期待される結果

解答 == B

ヒント

WHEREが効くのは集計の前か後か。

模範解答
B
解説

「misuse of aggregate」というエラーになる。WHEREが効く時点ではまだ集計されていないので、COUNT の結果は存在しない。

SQL08-D03 price の合計が 20000円を超えるカテゴリを、category と合計(別名「合計」)で取り出すSQLを書け。 コーディング★☆☆無料
期待される結果

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件で最多だが、合計金額では条件を満たさない。

SQL08-D04 平均単価が1万円を超えるカテゴリを取り出すSQLを完成させよ。 穴埋め★☆☆無料
コード
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 があるなら、その前になる。

SQL08-D05 句の正しい順番はどれか。
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でグループを絞る。順番を変えるとエラーになる。

SQL08-D06 商品が 3件以上あるカテゴリを、category と件数(別名「件数」)で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

1行。周辺機器 4

ヒント

HAVING COUNT(*) >= 3 と書く。

模範解答
SELECT category, COUNT(*) AS 件数
FROM products
GROUP BY category
HAVING COUNT(*) >= 3;
解説

条件を厳しくするとグループが減る。2件以上なら2グループ、3件以上なら1グループになる。

SQL08-D07 件数が2件以上のカテゴリを、件数の多い順に並べるSQLを完成させよ。 穴埋め★★☆無料
コード
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。

SQL08-D08 price > 1000 という条件は、WHERE と HAVING のどちらに書くべきか。
A. WHERE B. HAVING C. どちらでもよい D. 両方に書く
選択★★☆無料
期待される結果

解答 == A

ヒント

これは1行ごとに判定できる条件か、集計後の値か。

模範解答
A
解説

集計関数を使わない条件は WHERE に書く。先に行を減らしたほうが処理が速く、意図も明確になる。

SQL08-D09 price が入力済みの商品に限り、商品が 2件以上あるカテゴリを、category と件数(別名「件数」)で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

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件が先に除かれたため。

SQL08-D10 件数が 2件以上 かつ 合計が 20000円を超えるカテゴリを、category・件数(別名「件数」)・合計(別名「合計」)で取り出すSQLを書け。 コーディング★★☆無料
期待される結果

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問)

SQL08-S01 【主力カテゴリの抽出】商品が2件以上あるカテゴリについて、分類(NULLは「未分類」、別名「分類」)・商品数(別名「商品数」)・合計金額(別名「合計」)を、合計の大きい順に取り出すSQLを書け。 コーディング★★☆無料
期待される結果

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の標準構成になる。

SQL08-S02 【高単価カテゴリ】平均単価が 1万円を超えるカテゴリについて、category と平均単価(別名「平均単価」、小数第1位まで)を取り出す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 の条件には影響しない。表示の丸めと、判定に使う値は別物として扱われる。

SQL08-S03 【在庫額の大きいカテゴリ】在庫金額の合計(NULLは0として扱う)が 40万円以上のカテゴリを、category と在庫額(別名「在庫額」)で取り出し、在庫額の大きい順に並べるSQLを書け。 コーディング★★☆無料
期待される結果

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 と同じ式を書くのが確実。長くなるが、環境によっては別名が使えないため、この形が最も互換性が高い。

SQL08-S04 【WHERE と HAVING の使い分け】1000円以上の商品だけを対象に、商品が 2件以上あるカテゴリの category・件数(別名「件数」)・平均(別名「平均」、小数第1位まで)を取り出すSQLを書け。 コーディング★★★無料
期待される結果

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——迷ったら「集計関数を使うか」で決める。

SQL08-S05 【単一商品カテゴリの検出】商品が 1件しかないカテゴリを、分類(NULLは「未分類」、別名「分類」)と件数(別名「件数」)で取り出すSQLを書け。 コーディング★★★無料
期待される結果

1行。未分類 1

ヒント

HAVING COUNT(*) = 1 と書く。「以上」ではなく「ちょうど」なので = を使う。

模範解答
SELECT
  COALESCE(category, '未分類') AS 分類,
  COUNT(*) AS 件数
FROM products
GROUP BY 分類
HAVING COUNT(*) = 1;
解説

「少ないもの」を探すのもHAVINGの仕事。データの偏りや、登録漏れの疑いがあるグループを見つけるときに使う。

5仕上げ課題

SQL08-FINAL 【重点管理カテゴリの選定】在庫管理の責任者から「重点的に管理すべきカテゴリを選定してほしい」と依頼された。

選定条件
・対象は価格が入力済みの商品のみ(未入力は集計から除く)
・商品が 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の世界が一気に広がる。