Webサイト制作コースのお申し込みはこちら Webサイト制作コースのお申し込みはこちら

SQLのwhere句とhaving句の違い、評価順序が原因で出力されるエラーと原因についてまとめています。

SQLのwhereとhavingの違い

where句もhaving句も絞り込み条件を指定するためのSQLです。以下のように単純な条件指定の場合ですと、結果は全く同じになります。以下は、MySQLで実行しています。

mysql> select * from employees where emp_no=10001;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  |
+--------+------------+------------+-----------+--------+------------+
|  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
+--------+------------+------------+-----------+--------+------------+
1 row in set (0.00 sec)

mysql> select * from employees having emp_no=10001;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  |
+--------+------------+------------+-----------+--------+------------+
|  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
+--------+------------+------------+-----------+--------+------------+
1 row in set (0.09 sec)

ただし、一般的にwhereよりもhavingのほうがレスポンスが遅くなります。特に理由がなければ、絞り込み条件はwhere句で指定するのが良いでしょう。

【関連記事】
SQL having 集約関数の絞り込み whereよりもレスポンスが遅い理由とは? 

havingは、集計関数の絞り込み条件指定が可能

havingは、sum、max、avg、countなどの集計関数に対する絞り込み条件を指定することが可能です。

以下は、部署ごとの平均年収のうち、平均年収が7万ドル以上の部署のみを抽出するSQLです。

SELECT 
	departments.dept_name as bushomei, 
	avg(salary) as avg_kyuuryo
FROM 
	salaries 
	left join dept_emp ON dept_emp.emp_no = salaries.emp_no
	left join departments ON departments.dept_no = dept_emp.dept_no
WHERE
	salaries.to_date="9999-01-01"
group by
	bushomei
having
	avg_kyuuryo > 70000

+-----------+-------------+
| bushomei  | avg_kyuuryo |
+-----------+-------------+
| Sales     |  88842.1590 |
| Marketing |  80014.6861 |
| Finance   |  78644.9069 |
+-----------+-------------+
3 rows in set (3.45 sec)

where句で指定している salaries.to_date=”9999-01-01″ は、最新の年収金額を抽出するための条件です。whereとは別に、平均年収(avg_kyuuryo)が70000以上という条件をhaving句で指定しています。

whereとhavingの評価順序

実は、whereとhavingは評価順序が異なります。以下の順番で評価されるんですね。

  1. where
  2. group by
  3. having

SQLのavg関数は、group byの評価が終わって始めて値が抽出されます。そのため、whereでavg関数の値を条件に指定することはできないんですね。group byの評価が完了したあとのhaving句にはavgの値を指定できます。

実際に、whereとhavingの2箇所で指定した条件を、whereに指定して試してみましょう。havingの条件をwhereに追記すると、以下のエラーが出力されました。

SELECT 
	departments.dept_name as bushomei, 
	avg(salary) as avg_kyuuryo
FROM 
	salaries 
	left join dept_emp ON dept_emp.emp_no = salaries.emp_no
	left join departments ON departments.dept_no = dept_emp.dept_no
WHERE
	salaries.to_date="9999-01-01"
and avg_kyuuryo > 70000
group by
	bushomei;

ERROR 1054 (42S22): Unknown column 'avg_kyuuryo' in 'where clause'

havingではselectの列のエイリアス、avg_kyuuryoが使えたのにwhereでは使えないようで、avg_kyuuryoは不明なカラム名だというエラーになりました。

実は一般的なDBMSでは、selectでasを使って別名定義した名前はwhere句やhaving句では使えません。MySQLの拡張で、havingでのみ別名定義が使えるようになっているんですね。

それでは、別名ではなくavg関数をそのまま条件式に指定するとどうなるのでしょう?

and avg_kyuuryo > 70000の箇所をavg(salary) > 70000 に書き換えると、また別のエラーが出力されました。

ERROR 1111 (HY000): Invalid use of group function

グループ関数(集計関数)の使い方が間違っている、というエラーです。エラーメッセージからは直感的にわかりづらいですが、where句で集計関数は使えないというふうに考えて良いと思います。

まとめ

ポテパンダの一言メモ
  • where句とhaving句はどちらも絞り込み条件を指定できる
  • having句は、avg、max、sum、countなどの集計関数の絞り込み条件が指定可能
  • 一般的にhaving句はレスポンスが遅くなるので、集計関数以外の条件はwhereで指定する

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。