グループ化した集計結果に対して条件を指定するSQLの句。
HAVING句とは、GROUP BY でグループ化・集計したあとの結果に対して条件を指定し、条件に合うグループだけを残すためのSQLの句です。「件数が○件以上のグループだけ」「平均が○以上の部署だけ」といった絞り込みに使います。
身近な例で考えると、クラスごとの平均点を出したあとで「平均80点以上のクラスだけ表彰する」という選び方に似ています。一人ひとりではなく、集計したクラス単位の値を見て選ぶのがポイントです。
上のツールで▶ボタンを押すと、グループ化して集計したあと、HAVING の条件によってグループが残ったり除外されたりする様子を確認できます。
どちらも「条件で絞り込む」点は同じですが、効くタイミングと対象が違います。
| 項目 | WHERE | HAVING |
|---|---|---|
| 効くタイミング | 集計の前 | 集計の後 |
| 絞る対象 | 1行ずつ | グループ(集計値) |
| 集計関数 | 使えない | 使える(COUNT等) |
例えば「給与30万円未満の人を除いて集計したい」なら WHERE salary >= 30、「集計した平均が40以上の部署だけ残したい」なら HAVING AVG(salary) >= 40 です。WHERE には COUNT や AVG などの集計関数を書けない、という点も大きな違いです。上のツールの「WHEREとHAVINGの併用」シナリオで両方の動きを見比べられます。
SQL を書く順番(SELECT…FROM…WHERE…GROUP BY…HAVING…ORDER BY)と、実際に処理される順番は違います。データベースは内部的に次の順で処理します。
・① WHERE:集計前に1行ずつ絞り込む
・② GROUP BY:同じ値の行をグループにまとめる
・③ 集計:各グループで COUNT・AVG などを計算
・④ HAVING:集計結果のグループを条件で絞る
HAVING は「集計が終わってはじめて分かる値(件数・合計・平均など)」に条件をかけるので、必ず集計のあとに働きます。だからこそ COUNT(*) や AVG(salary) のような集計関数を条件式に書けるのです。上のツールの最終ステップで、集計後にグループが絞り込まれて結果が確定する流れを確認してください。
WHERE と HAVING は同じ SQL の中で一緒に使えます。それぞれが別のタイミングに働くので、役割が重なりません。
例えば「給与30万円未満の人を最初に除いてから、残った人で部署ごとに集計して、2人以上の部署だけ表示する」という2段階の絞り込みができます。
・WHERE salary >= 30:まず低給与の行を集計対象から外す(個人レベル)
・HAVING COUNT(*) >= 2:集計後に人数の少ない部署を除く(グループレベル)
なぜ分けるかというと、WHERE で除いた行は集計にも含まれないからです。給与30万未満の人を先に除けば、その人たちは COUNT にも AVG にも入りません。この2つを組み合わせると「誰を集計対象にするか」と「どのグループを最終結果に残すか」を別々に制御できます。上のツールの「WHEREとHAVINGの併用」シナリオで確認してください。
集計関数(しゅうけいかんすう)とは、グループ内の複数の値から1つの値を計算する関数です。HAVING の条件式にはこれらを使います。WHEREの条件式には使えないことも合わせて覚えておきましょう。
| 関数 | 意味 | 使い方の例 |
|---|---|---|
| COUNT(*) | グループの行数 | HAVING COUNT(*) >= 2 |
| SUM(列) | 合計値 | HAVING SUM(salary) > 100 |
| AVG(列) | 平均値 | HAVING AVG(salary) >= 40 |
| MAX(列) | 最大値 | HAVING MAX(score) >= 90 |
| MIN(列) | 最小値 | HAVING MIN(score) >= 60 |
なぜ WHERE では集計関数が使えないかというと、WHERE が動くタイミングには、まだグループも集計も存在しないからです。「合計がいくつか」はグループを作って計算して初めて分かります。よって、集計した値に条件をかけたいときは必ず HAVING を使います。