はじめに
SQLを触っていると、基本的な構文は理解しているつもりでも、WHEREとHAVINGの違いのように、いざ説明しようとすると曖昧なままになっている部分があります。
そこで今回は、前回の記事に続いて「理解しているつもりで曖昧だった部分」を自分なりにまとめてみました。復習も兼ねていますが、同じようにSQLを学習している方の参考になれば嬉しいです。
WHEREとHAVINGの役割の違い
結論から述べると、両者の役割の違いは以下の通りです。
- WHERE:行を絞り込む(グループ化前のフィルタ)
- HAVING:グループを絞り込む(グループ化後のフィルタ)
この違いをより深く理解するために、次節では両者の実行順序について詳しく解説します。
SQLの処理順序
WHEREとHAVINGの違いをより直感的に理解するために、数学と物理の合計点が160点以上の生徒を抽出するSQLを例に、実際の処理順序を追ってみましょう。
SELECT
s.student_id, SUM(r.score) total
FROM
students s
INNER JOIN
results r
ON s.student_id = r.student_id
WHERE
r.subject IN ('Mathematics', 'Physics')
GROUP BY
s.student_id
HAVING
SUM(r.score) >= 160;
① FROM(テーブルの読み込み)
FROM
FROM students s
INNER JOIN results r
ON s.student_id = r.student_id
- students と results を結合
- student_id が一致する行だけが残る(INNER JOIN)
② WHERE(グループ化前のフィルタ)
WHERE
WHERE r.subject IN ('Mathematics', 'Physics')
- 結合後のテーブルから「数学」と「物理」の行だけが残る
- 他の科目(英語・化学など)はここで除外される
③ GROUP BY(グループ化)
GROUP BY
GROUP BY s.student_id
- 学生ごとに行をまとめる
- この時点で「student_id ごとのグループ」ができる
④ HAVING(グループ化後のフィルタ)
HAVING
HAVING SUM(r.score) >= 160;
- グループ化後の集計結果に対して条件を適用
- 「数学」+「物理」の合計点が 160点以上の学生だけを残す
⑤ SELECT(表示する列を決定)
SELECT
SELECT s.student_id, SUM(r.score) total
- 最終的に抽出する列を決める
具体例で比較
WHEREの役割
| student_id | subject | score |
|---|---|---|
| 001 | Mathematics | 80 |
| 001 | Physics | 90 |
| 001 | English | 90 |
| 002 | Mathematics | 70 |
| 002 | Physics | 80 |
| 002 | English | 100 |
数学・物理以外の行を除外。
| student_id | subject | score |
|---|---|---|
| 001 | Mathematics | 80 |
| 001 | Physics | 90 |
| 002 | Mathematics | 70 |
| 002 | Physics | 80 |
HAVINGの役割
| student_id | SUM(r.score) |
|---|---|
| 001 | 170 |
| 002 | 150 |
合計160点未満のグループを除外。
| student_id | SUM(r.score) |
|---|---|
| 001 | 170 |
使用する際の注意点
よくある間違い①
HAVING句で行レベルの条件を書いてしまう
よくある間違い①
HAVING r.subject IN ('Mathematics', 'Physics')
HAVINGは「グループ化後の条件」なので、行レベルのsubjectを直接絞るのは不適切。
→ これはWHERE句に書くべき条件。
よくある間違い②
WHERE句で集計関数(SUM, COUNTなど)を使おうとしてエラー
よくある間違い②
WHERE SUM(r.score) >= 160
WHERE は「グループ化前」に処理されるため、SUM はまだ計算されていない。
→ これはHAVING句に書くべき条件。
まとめ
WHEREとHAVINGの違いは以下の2点です。
- WHERE:行を絞り込む(グループ化前のフィルタ)
- HAVING:グループを絞り込む(グループ化後のフィルタ)
SQLの処理順序を理解することで、両者の適切な使用方法を自然に正しく使い分けることができるようになるはずです。