Oracle Database の SQL を書く際、初心者の方が最も混同しやすいのが WHERE 句と HAVING 句の違いです。どちらも「データの絞り込み」を行いますが、適用されるタイミングと対象が明確に異なります。
本記事では、scott スキーマの EMP テーブルを使用し、WHERE(行の絞り込み)と HAVING(集計結果の絞り込み)の決定的な違いと、正しい使い分けを解説します。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
結論・違いのクイックリファレンス
最大の違いは「集計(GROUP BY)」の前か後か、です。
| 項目 | WHERE 句 | HAVING 句 |
| 対象 | 行 (Row) | グループ (Group) |
| タイミング | 集計前 (GROUP BYより先) | 集計後 (GROUP BYより後) |
| 集計関数の使用 | 不可 (SUM, AVGなどは使えない) | 必須 (条件に集計関数を使う) |
| 役割 | 元データを減らす(基礎フィルタ) | 集計結果を選別する(分析フィルタ) |
【この記事でわかること】
- WHERE と HAVING の正しい実行順序
ORA-00934エラーの原因と対策- パフォーマンスを意識した SQL の書き方
1. 背景と基礎:処理の流れを理解する
Oracle データベースが SQL を解釈・実行する順序を理解すると、違いが明確になります。
SQL の評価順序
- FROM: テーブルを特定
- WHERE: 不要な行を捨てる【ここ!】
- GROUP BY: 残った行をグループ化・集計
- HAVING: 条件に合わないグループを捨てる【ここ!】
- SELECT: 列を表示
2. 実践:SCOTTスキーマでの検証
SCOTT.EMP テーブル(従業員表)を使って、挙動の違いを実機で確認します。
SCOTTサンプルスキーマは以下を実行することでインポートおよび使用が可能です。
$ sqlplus / as sysdba
SQL> @?/rdbms/admin/utlsampl.sql
$ sqlplus scott/tiger
データ準備
まず、EMP テーブルの全体像を把握します。
-- 全件確認
SELECT DEPTNO, JOB, SAL FROM EMP ORDER BY DEPTNO;
SQL> SELECT DEPTNO, JOB, SAL FROM EMP ORDER BY DEPTNO;
DEPTNO JOB SAL
---------- --------- ----------
10 MANAGER 2450
10 PRESIDENT 5000
10 CLERK 1300
20 MANAGER 2975
20 ANALYST 3000
20 CLERK 1100
20 CLERK 800
20 ANALYST 3000
30 SALESMAN 1250
30 SALESMAN 1500
30 SALESMAN 1600
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 1250
14 rows selected.
シチュエーション 1:WHERE 句(集計前の絞り込み)
目的: 「営業職(SALESMAN)」だけを対象にして、部署ごとの給与合計を知りたい。 この場合、集計する前に営業職以外を除外する必要があります。
SELECT
DEPTNO,
SUM(SAL) AS TOTAL_SAL
FROM EMP
WHERE JOB = 'SALESMAN' -- 集計前に「営業マン」だけに行を絞る
GROUP BY DEPTNO;
実行結果:
SQL> SELECT
2 DEPTNO,
3 SUM(SAL) AS TOTAL_SAL
4 FROM EMP
5 WHERE JOB = 'SALESMAN'
6 GROUP BY DEPTNO;
DEPTNO TOTAL_SAL
---------- ----------
30 5600
解説: WHERE 句が先に働き、営業職以外のデータ(CLERKやMANAGERなど)が計算対象から外れました。その結果、営業職が存在する 30部門だけが集計されました。
シチュエーション 2:HAVING 句(集計後の絞り込み)
目的: 「部署ごとの給与合計」を出し、その結果が「9000以上」の部署だけ表示したい。 合計値は集計してみないと分からないため、HAVING を使います。
SELECT
DEPTNO,
SUM(SAL) AS TOTAL_SAL
FROM EMP
GROUP BY DEPTNO -- まず全職種で集計する
HAVING SUM(SAL) >= 9000; -- 集計結果を見て判定する
実行結果:
SQL> SELECT
2 DEPTNO,
3 SUM(SAL) AS TOTAL_SAL
4 FROM EMP
5 GROUP BY DEPTNO
6 HAVING SUM(SAL) >= 9000;
DEPTNO TOTAL_SAL
---------- ----------
30 9400
20 10875
解説: 一度すべての部署で合計を計算した後、TOTAL_SAL が 9000 未満だった 10部門(合計8750)が結果から除外されました。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
3. 応用:WHERE と HAVING の併用
実務では両方を組み合わせるケースが頻出します。
目的: 「管理者(MANAGER)を除外したうえで、平均給与が 1500 以上の部署を知りたい」
SELECT
DEPTNO,
COUNT(*) AS EMP_COUNT,
AVG(SAL) AS AVG_SAL
FROM EMP
WHERE JOB <> 'MANAGER' -- 1. まずMANAGERを除外 (行フィルタ)
GROUP BY DEPTNO -- 2. 部署ごとに集計
HAVING AVG(SAL) >= 1500; -- 3. 平均1500以上を残す (グループフィルタ)
実行結果:
SQL> SELECT
2 DEPTNO,
3 COUNT(*) AS EMP_COUNT,
4 AVG(SAL) AS AVG_SAL
5 FROM EMP
6 WHERE JOB <> 'MANAGER'
7 GROUP BY DEPTNO
8 HAVING AVG(SAL) >= 1500;
DEPTNO EMP_COUNT AVG_SAL
---------- ---------- ----------
10 2 3150
20 4 1975
ポイント: もし WHERE を使わず HAVING だけですべて行おうとすると、除外したい MANAGER の給与まで平均計算に含まれてしまい、正しい分析結果が得られません。
4. トラブルシューティング
よくあるエラー:ORA-00934
初心者が最もよく遭遇するエラーです。
エラーとなる SQL:
SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE SUM(SAL) > 10000 -- NG: WHERE句で集計関数は使えません
GROUP BY DEPTNO;
SQL> SELECT DEPTNO, SUM(SAL)
2 FROM EMP
3 WHERE SUM(SAL) > 10000
4 GROUP BY DEPTNO;
WHERE SUM(SAL) > 10000
*
ERROR at line 3:
ORA-00934: group function is not allowed here
原因と対処: WHERE 句は「行」を評価する段階なので、まだ SUM(合計)は存在していません。集計結果に対する条件は必ず HAVING に移動してください。
5. 運用・監視・セキュリティ上の注意
パフォーマンスへの影響
「結果が同じなら、どちらで絞り込んでも良いのでは?」と思うかもしれませんが、パフォーマンス(検索速度)には大きな差が出ます。
- 原則: 可能な限り WHERE 句で先に絞り込む。
- 理由:
GROUP BYはデータのソートやハッシュ処理を伴う重い処理です。WHEREで事前に行数を減らしておけば、集計処理の負担が軽くなり、メモリ使用量も削減できます。
6. FAQ:よくある質問
Q1. SELECT句の列別名(Alias)を HAVING で使えますか?
A. Oracle 19c 以前では使えません。HAVING Total_Sal > 1000 と書くとエラー(ORA-00904)になります。HAVING SUM(SAL) > 1000 と書く必要があります。 (※Oracle 23ai からは別名の使用が可能になりました)
Q2. HAVING 句だけで WHERE の代わりはできますか?
A. 文法上は GROUP BY 列に対する条件であれば可能ですが、推奨されません。 例: HAVING DEPTNO = 10 は動きますが、全データを集計した後に絞り込むため非効率です。単一の行の値で判断できるものは WHERE に書きましょう。
Q3. WHERE と HAVING はどちらが先に実行されますか?
A. 必ず WHERE 句 が先です。 実行順序: FROM → WHERE → GROUP BY → HAVING → SELECT
まとめ
- 対象の違い:
WHEREは「行」、HAVINGは「集計結果」。 - 使い分け: 集計関数(SUM, AVG等)の条件判定は
HAVING、それ以外はWHERE。 - パフォーマンス:
WHEREで無駄なデータを早めに捨てるのが SQL チューニングの基本。 - エラー対策:
WHEREにSUMは書けない(ORA-00934)。
まずは WHERE でデータを綺麗にし、その後に GROUP BY と HAVING で料理(集計)するイメージを持つと覚えやすいでしょう。
本記事は Oracle Database 19c を対象に解説します(他バージョンは画面や既定値が異なる場合があります)。
[参考]
Oracle Database SQL言語リファレンス 19c
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?




コメント