集計結果で絞り込む HAVING句

データベース

集計結果に対して絞り込み条件を設定するにはHAVING句を利用します。

HAVING句の構文

HAVING 条件式

抽出条件として、WHERE句と同様の各種条件式を記述することが出来ます。
多くの入門書では、HAVING句は必ずGROUP BY句と組み合わせて使うかのように記載されているのですが、実はGROUP BY句なしにHAVING句を用いても文法違反にはなりません。
WHERE句とHAVING句の違いは、評価されるタイミングです。

以下のような、ここまでに学んだ句をすべて使ったSQLを考えます。

SELECT 関数 FROM テーブル WHERE 条件式1 GROUP BY カラム名 HAVING 条件式2;

このSQLの実行順序は以下のようになります。

1.テーブルから、WHERE句の条件式1を満たすレコードが抽出される。
2.1で抽出されたレコードがGROUP BY句のカラム名でグループ化される
3.2でグループ化されたグループごとに関数の値が求められる
4.3の結果からHAVING句の条件式2を満たすものが抽出される

つまり、
最初にテーブルから操作対象となるレコードを抽出する条件を記述するには WHERE句
グループ化や関数による計算の結果について抽出条件を記述するには HAVING句
と使い分けているのです。

HAVING句の例

例1
SQL
SELECT subject, AVG(score) AS average FROM examination 
        GROUP BY subject HAVING average>=70;

科目(subject)ごとに平均点(scoreの平均値)を求め、それが70以上のものだけを抽出しています。

実行結果
例2

HAVING句の条件式にグループ関数を書くことも出来ます。

SQL
SELECT subject, AVG(score) AS average FROM examination 
        GROUP BY subject HAVING AVG(score)>=70;

実行結果は例1と同じです。

例3

グループ化も計算も行わない場合はWHERE句とHAVING句のどちらを用いても結果に差が出ません。

SQL
SELECT student_id,subject,score FROM examination WHERE score>=70;

または

SQL
SELECT student_id,subject,score FROM examination HAVING score>=70;
実行結果

2つのSQLは同じ結果になります。
(結果が同じになるとはいえ、通常このような場合はWHERE句を使います)

例4(WHERE句では不適切な例)
SQL
SELECT subject AS `科目`, AVG(score) AS average FROM examination 
        GROUP BY subject WHERE average>=70;

このように記述すると文法違反になります(WHERE句はGROUP BY句より後には書けません)
※phpmyadminでは日本語のカラム名を使うとエラーが表示されないことがあるという不具合があるので`平均点`ではなくaverageとしています

例5(WHERE句では不適切な例)
SQL
SELECT subject AS `科目`, AVG(score) AS average FROM examination 
        WHERE average>=70 GROUP BY subject;

この例では文法違反にはなりませんが、WHERE句のaverageというカラム名が未定義であるというエラーになります。WHERE句の実行順序がグループ化・averageの計算よりも前になるためです。

練習問題

テーブルexaminationについて、以下の内容を求めるSQLを記述しなさい。

1.最高点(scoreの最大値)が80点以上であった科目(subject)

2.受験者数(レコード数)が4人に満たなかった科目(subject)

コメント

タイトルとURLをコピーしました