コマンド道場

HAVING 句の使い方

まず「まとめる」があって、その後に HAVING が効く

shain社員

busho_idsalary
1980000
2720000
2530000
2520000

GROUP BYまとめた結果

busho_idcount(salary)
11
24
34

GROUP BY busho_id

  • 社員 16 が、6にまとまります(同じ busho_id の行が 1 行になる)。
  • count(salary)まとまりごとに計算した値で、元の表には無い列です。

HAVING は、この右側の表に対して条件を付けます。左側(元の行)には効きません。

HAVING は「まとめた後の行」に条件を付ける場所です。 WHERE はまとめる前、HAVING はまとめた後。この順番だけが両者の違いで、そこから使い分けがすべて決まります。

主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2

製品ごとの対応表(実測)を見る

このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。

01評価される順番がすべて

結論: `WHERE` → `GROUP BY` → `HAVING` の順に処理されます。

この順番から、次のことが自動的に決まります。

  • WHERE では集約関数が使えない(まだまとめていないので count(*) の値が存在しない)
  • HAVING では集約した値が使える(すでにまとめた後だから)
  • WHERE で落とした行は、集計にも入らない

「在籍者だけで数える」なら WHERE。「2 人以上の部署だけ出す」なら HAVING です。

1 行ずつ、何をしているか
  1. SELECT busho_id, count(*) AS ninzuまとまりごとに数える
  2. FROM shainどの表を見るか
  3. WHERE taishoku_on IS NULL① まとめる前に絞る
  4. GROUP BY busho_id② まとめる
  5. HAVING count(*) >= 3③ まとめた後に絞る
  6. ORDER BY ninzu DESC並び順

①②③ の順に効きます。この順番を思い出せば、どちらに書くかで迷いません。

在籍者だけで数え、3 人以上の部署に絞る
SELECT busho_id, count(*) AS ninzu
FROM shain
WHERE taishoku_on IS NULL
GROUP BY busho_id
HAVING count(*) >= 3
ORDER BY ninzu DESC, busho_id;
busho_idninzu
24
33

2

02⚠️ よくある間違い:WHERE に集約関数を書くとエラーになる

「3 人以上の部署」を出したくて WHERE count(*) >= 3 と書くと、エラーになります

WHERE が効く時点ではまだ行がまとまっていないので、count(*) という値がそもそも存在しないためです。

エラーメッセージは「集約関数は WHERE では使えない」と、原因をそのまま言ってくれます。`HAVING` に移せば直ります。

わざとエラーになる例
SELECT busho_id, count(*)
FROM shain
WHERE count(*) >= 3
GROUP BY busho_id;
ERROR: aggregate functions are not allowed in WHERE

「集約関数は WHERE 句では使えない。おそらく HAVING に書くべき」と提案までしてくれます。

03⚠️ よくある間違い:逆に、まとめる前の条件を HAVING に書かない

HAVING にも普通の列の条件は書けてしまいます。エラーにはなりません。ただし書くべきではありません

理由は 2 つあります。

  • 意味が変わることがあるWHERE なら集計から除かれますが、HAVING はまとまった後の判定なので、集計値そのものは除外前の値のままになりえます
  • 無駄が多い。先に絞れる行を最後まで持ち回るので、行数が多いほど遅くなります

行の条件は `WHERE`、集約の条件は `HAVING` と機械的に割り振ってください。

集約した値で絞る(HAVING の正しい使い方)
SELECT busho_id, count(*) AS ninzu, max(salary) AS saikou
FROM shain
GROUP BY busho_id
HAVING max(salary) >= 600000
ORDER BY busho_id;
busho_idninzusaikou
11980000
24720000
34700000
43650000
52610000

5

「最高給与が 60 万以上の部署」は、まとめないと分かりません。だから HAVING です。

04⚠️ よくある間違い:SELECT で付けた別名が使えるかは製品による

HAVING ninzu >= 3 のように別名で書けるかどうかは製品によって違います。標準では使えず、PostgreSQL でもエラーになります。

理由は評価順です。HAVINGSELECT より前に効くので、その時点ではまだ別名が作られていません。

確実なのは、式をそのまま書くことです。HAVING count(*) >= 3 と書けばどの製品でも通ります。

ORDER BYSELECT の後なので、別名が使えます。ここが紛らわしいところです。)

わざとエラーになる例(別名を HAVING で使う)
SELECT busho_id, count(*) AS ninzu
FROM shain
GROUP BY busho_id
HAVING ninzu >= 3;
ERROR: column "ninzu" does not exist

「ninzu なんて列は無い」と言われます。HAVING の時点では別名がまだ存在しません。

05GROUP BY 無しでも書ける

GROUP BY を書かずに集約関数を使うと、表全体が 1 つのまとまりになります。この場合も HAVING は使えます。

条件が真なら 1 行、偽なら 0 行が返ります。「全体の件数が 10 件を超えていたら結果を返す」といった、しきい値の判定に使えます。

使う機会は多くありませんが、HAVING が「まとまりに対する条件」であることの確認になります。

全体で 10 人以上いるときだけ結果を返す
SELECT count(*) AS zenin, avg(salary)::numeric(10,0) AS heikin
FROM shain
HAVING count(*) >= 10;
zeninheikin
18542003

1

条件を満たすので 1 行返ります。>= 100 に変えると 0 行になります(その場に打って試せます)。

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

関連するトピック

根拠(一次情報)