WHERE句とHAVING句

WHERE句とHAVING句

WHERE句もHAVING句も、条件抽出を行うためのものです。
ただし、WHERE句とHAVING句では、用法が異なります。

WHERE句は、FROM によってテーブルから抽出されたデータに条件を適用します。
(WHERE句はGROUP BYより前に評価されます。)
一方、HAVING句は、GROUP BYによってグルーピングされた各グループに対して条件を適用します。

つまり、テーブルのデータ全体に対して、何か条件を適用したい場合はWHERE句を利用します。
(性別のカラムが'男'のデータだけ抽出する、など)
GROUP BYによってまとめられた、各グループごとに何か条件を適用したい場合はHAVING句を利用します。
都道府県別で平均年齢が40歳以上の都道府県だけを抽出する、など)

SQL の評価順序

SQL は以下の順序で評価します。
(WHERE と HAVING に関連してるもののみ)

  1. FROM (テーブルからのデータ抽出)
  2. WHERE (条件抽出)
  3. GROUP BY (グループにまとめる)
  4. HAVING (グループごとに条件適用)
  5. SELECT (カラム選択)

ということで、WHERE句はGROUP BYより前に条件抽出を、
HAVING句はGROUP BYより後で条件抽出を行います。

参考: SELECT文の評価順序の話 - Qiita

サンプル

以下のテーブルで試してみます。

id name gender birthregion height
1 山田 勝 関東 172
2 佐藤 瞳 関東 160
3 高橋 桃子 関西 144
4 高橋 愛美 関西 152
5 鈴木 博文 関東 180
6 藤田 拓也 関東 168
7 小林 晶子 関東 155
8 橋本 浩之 関西 170
9 和田 博 関西 182
10 中村 幸子 関西 160

まずは、WHERE句から試してみます。

SELECT *
FROM students
WHERE gender = '';

結果

 id |   name    | gender | birthregion | height 
----+-----------+--------+-------------+--------
  1 | 山田 勝   | 男     | 関東        |    172
  5 | 鈴木 博文 | 男     | 関東        |    180
  6 | 藤田 拓也 | 男     | 関東        |    168
  8 | 橋本 浩之 | 男     | 関西        |    170
  9 | 和田 博   | 男     | 関西        |    182
(5 rows)

男性だけを抽出することができました。

続いて、HAVING句を試してみます。
HAVING句はGROUP BYでまとめたグループごとに条件を適用しますので、
性別ごとにグループにまとめて、平均身長が160を超えている性別のみを表示します。

SELECT gender, AVG(height)
FROM students
GROUP BY gender
HAVING AVG(height) > 160;

結果

 gender |         avg          
--------+----------------------
 男     | 174.4000000000000000
(1 row)

男性の平均身長は174.4cmなので、男性は表示されます。

最後に、WHERE句とHAVING句を両方つかってみます。

SELECT birthregion, AVG(height)
FROM people
WHERE gender = ''
GROUP BY birthregion
HAVING AVG(height) > 175;

結果

 birthregion |         avg          
-------------+----------------------
 関西        | 176.0000000000000000
(1 row)

終わり