問題
SQLのGROUP BY句と組み合わせて使用し、グループ化後のレコードに条件を指定するための句はどれか。
答え合わせ
- A
- B
- C
- D
自信の3択
えらぶと、この端末に記録します(登録はいりません)
解説
正解は「HAVING」です。
SQLで「グループにまとめてから条件をつけたい」ときに使う句です。たとえば:
```sql
SELECT 部署, AVG(給料) FROM 社員
GROUP BY 部署
HAVING AVG(給料) > 500000;
```
これは「部署ごとに平均給料を出して、平均が50万円超えの部署だけ表示」です。
WHEREは「グループにする前」、HAVINGは「グループにした後」と覚えましょう。
ORDER BYは並び替え、DISTINCTは重複削除で別の役割です。
正解は b「HAVING」です。
SQLの問い合わせは以下の順序で評価されます(論理的処理順序):
```
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
```
このうち:
- WHERE:FROM後の各行に対する条件。集約関数(SUM, COUNT, AVG等)は使えない。
- GROUP BY:指定列でグループ化し集約関数を適用可能にする。
- HAVING:GROUP BY後の集約結果に対する条件。集約関数を使える。
- ORDER BY:最終結果の並び替え。
- DISTINCT:重複行の削除。
例:
```sql
SELECT department, AVG(salary) AS avg_sal
FROM employees
WHERE hire_date >= '2020-01-01' -- 個別行の条件
GROUP BY department
HAVING AVG(salary) > 500000 -- 集約後の条件
ORDER BY avg_sal DESC;
```
ここで「平均給与50万円超」を WHERE に書くとエラーです(集約関数は WHERE では使えない)。HAVING で書きます。
よくある誤り:
- WHERE と HAVING の混同 → 集約関数を使う条件は必ず HAVING
- HAVING 単独での使用 → GROUP BY なしで HAVING を書くと全体を1グループとみなす(一部DBMSのみ)
- 集約関数のネスト不可 → `HAVING SUM(AVG(x)) > 10` のような書き方は不可
AP午前ではSQL構文と論理処理順序が頻出(シラバス「データベース・関係データベース言語」)。午後問題ではSQLの読解・生成が問われるので、ウィンドウ関数(OVER句)、CTE(WITH句)、JOIN種別との組合せも合わせて押さえましょう。
正解は b「HAVING」です。
HAVING句は単純な構文事項ですが、RDBMSの問合せ最適化、論理処理順序、現代SQLの拡張機能の理解には不可欠なテーマです。上級者として押さえるべきは「論理 vs 物理処理順序」「ウィンドウ関数との使い分け」「実行計画への影響」の3点です。
1. 論理処理順序 vs 物理処理順序
SQL標準は論理処理順序を以下の通り定義しています:
```
1. FROM (含 JOIN)
2. WHERE
3. GROUP BY
4. HAVING
5. SELECT (含 集約関数 + ウィンドウ関数)
6. DISTINCT
7. ORDER BY
8. OFFSET / FETCH (LIMIT)
```
しかし物理処理順序はオプティマイザが自由に決めます。例えば PostgreSQL では以下の最適化が行われます:
- Predicate pushdown:WHEREや HAVING のうち、GROUP BY列のみで判定可能な条件を GROUP BY 前にプッシュダウン。
- Projection pushdown:必要列のみを下層から取得。
- Index-only scan:WHERE/HAVING/集約をすべてインデックスのみで処理。
- HashAggregate vs GroupAggregate:ハッシュテーブル方式と ソート方式 の選択。
2. ウィンドウ関数との使い分け
HAVINGは「グループ化後の集約結果フィルタ」ですが、ウィンドウ関数(OVER句)は「グループ化せずに行ごとに集約値を計算」できます:
```sql
-- HAVING: 部署平均50万円超の部署のみ
SELECT department, AVG(salary) FROM employees
GROUP BY department HAVING AVG(salary) > 500000;
-- ウィンドウ関数: 部署平均との差分を全行に付与
SELECT name, salary, AVG(salary) OVER (PARTITION BY department) AS dept_avg
FROM employees;
```
ウィンドウ関数は集約とは別パスで処理され、行を消費しません。HAVINGは行を絞り込みます。両者を組み合わせることも可能:
```sql
WITH ranked AS (
SELECT department, name, salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS r
FROM employees
)
SELECT department, name, salary FROM ranked WHERE r <= 3;
```
これで「各部署の上位3名」を抽出できます。GROUP BY + HAVING では「上位N」のような順序依存のフィルタが書けないため、ウィンドウ関数とCTE(WITH句)の組合せが標準的解法です。
3. 実行計画への影響
PostgreSQLで `EXPLAIN ANALYZE` を使うと、HAVING句がどの段階で評価されるかが分かります:
```
HashAggregate (cost=... rows=... width=...)
Group Key: department
Filter: (avg(salary) > 500000)
-> Seq Scan on employees
```
`Filter:` がHAVING句に相当します。これがインデックス利用可能な条件ならば、PostgreSQLのオプティマイザは可能な範囲でプッシュダウンします。
4. SQL/JSON と HAVING
PostgreSQL 16以降ではSQL/JSON標準のサポートが進み、JSONB列の集約とHAVINGを組み合わせた問い合わせが可能です:
```sql
SELECT jsonb_array_elements(data->'tags') AS tag, COUNT(*) AS cnt
FROM products
GROUP BY tag
HAVING COUNT(*) > 100;
```
5. パフォーマンス・チューニングの観点
- HAVING句の中でサブクエリを書くと相関サブクエリとなりN+1問題が発生しやすい。CTE化を推奨。
- インデックスは HAVING の集約関数の引数列に張ると有効(部分集約のIndex-only scan)。
- マテリアライズドビューで集約結果を事前計算し、HAVINGを通常のWHEREに置き換える設計も有効。
- window関数 vs GROUP BY:行を残したい場合はウィンドウ関数、絞り込みたい場合はGROUP BY+HAVING。
6. 標準SQL以外の方言
- MySQL:HAVING 句で SELECT 句のエイリアスを参照可能(標準SQLでは不可)。
- PostgreSQL:CTE と LATERAL JOIN が強力で、HAVING の代替表現が多い。
- BigQuery:QUALIFY 句でウィンドウ関数の結果に対する HAVING 相当を提供。
7. AP午後問題でのSQL読解
AP午後のデータベース問題では、ER図とSQL断片から「業務要件」を読み取る能力が問われます。HAVING句が出てくる場面は典型的に「集約レポート」「ランキング」「異常検知」で、GROUP BY 列と集約関数の組合せから業務文脈を推測する訓練が得点に直結します。
実務的示唆:分析クエリの95%はGROUP BY + HAVING または ウィンドウ関数で書けます。両者を正しく使い分けられるかが SQL習熟度の試金石です。HAVING句を「集約後フィルタ」と一言で覚えるのは入門レベル、実行計画と組合せて最適化できるのが上級レベルです。
出典と作り方
出典:IPA(情報処理推進機構)公式 応用情報技術者試験(AP) 令和6年度 秋期 問2/ 公的機関配布資料につき出典明記の上引用。解説は合格ナビによる独自AI解説です。

