「部署ごとの給与合計を出したい」「平均点が80点以上のクラスだけ抽出したい」。
このようにデータをグループ化して集計し、さらにその結果に対して条件を指定する場合、Oracle SQL では GROUP BY と HAVING を使用します。
本記事では、GROUP BY(グループ化)と HAVING(集計後の絞り込み)の基本構文から、初心者が必ず躓く WHERE 句との使い分けまで、scott スキーマの実例を使って解説します。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
結論・構文のクイックリファレンス
集計と絞り込みを行う際の SQL の基本形と評価順序は以下の通りです。
基本構文
SELECT 列名, 集計関数(列名)
FROM テーブル名
WHERE 集計前の絞り込み条件
GROUP BY グループ化したい列名
HAVING 集計後の絞り込み条件
ORDER BY 並び替え;
実行(評価)される順序
- FROM: 対象テーブルを見る
- WHERE: 行単位でフィルタリング(集計前)
- GROUP BY: データをグループにまとめる
- HAVING: グループ単位でフィルタリング(集計後)
- SELECT: 結果を表示
- ORDER BY: 並び替え
1. 背景と基礎:GROUP BY と HAVING の仕組み
GROUP BY とは?
指定した列の値が同じデータを「1つのグループ」にまとめます。グループ化することで、その単位ごとに SUM(合計)や AVG(平均)などの集計関数を適用できるようになります。
HAVING とは?
集計した結果に対して条件を指定します。「合計が〇〇以上のグループ」といった指定は、WHERE 句ではなく HAVING 句で行う必要があります。
WHERE と HAVING の決定的な違い
- WHERE: 元のデータ(行)を絞り込む。「集計前」に不要なデータを捨てます。
- HAVING: 集計結果(グループ)を絞り込む。「集計後」に条件判定します。
2. 実践:SCOTTスキーマでの検証
ここからは Oracle Database の標準サンプルである SCOTT スキーマの EMP(従業員)テーブルを使用して動作を確認します。
前提環境:
- Oracle Database 19c
- SCOTTユーザー(または同等のテーブルを持つユーザー)で接続
SCOTTサンプルスキーマは以下を実行することでインポートおよび使用が可能です。
$ sqlplus / as sysdba
SQL> @?/rdbms/admin/utlsampl.sql
$ sqlplus scott/tiger
データ確認
まずは集計前の生データを確認します。
SELECT EMPNO, ENAME, JOB, SAL, DEPTNO FROM EMP ORDER BY DEPTNO;
実行結果:
SQL> SELECT EMPNO, ENAME, JOB, SAL, DEPTNO FROM EMP ORDER BY DEPTNO;
EMPNO ENAME JOB SAL DEPTNO
---------- ---------- --------- ---------- ----------
7782 CLARK MANAGER 2450 10
7839 KING PRESIDENT 5000 10
7934 MILLER CLERK 1300 10
7566 JONES MANAGER 2975 20
7902 FORD ANALYST 3000 20
7876 ADAMS CLERK 1100 20
7369 SMITH CLERK 800 20
7788 SCOTT ANALYST 3000 20
7521 WARD SALESMAN 1250 30
7844 TURNER SALESMAN 1500 30
7499 ALLEN SALESMAN 1600 30
7900 JAMES CLERK 950 30
7698 BLAKE MANAGER 2850 30
7654 MARTIN SALESMAN 1250 30
14 rows selected.
3. 手順・実装:基本から応用まで
パターン1:GROUP BY の基本(部署ごとの給与合計)
部門番号(DEPTNO)ごとにグループ化し、それぞれの給与(SAL)合計を算出します。
SELECT
DEPTNO,
SUM(SAL) AS TOTAL_SALARY
FROM EMP
GROUP BY DEPTNO
ORDER BY DEPTNO;
実行結果:
SQL> SELECT
2 DEPTNO,
3 SUM(SAL) AS TOTAL_SALARY
4 FROM EMP
5 GROUP BY DEPTNO
6 ORDER BY DEPTNO;
DEPTNO TOTAL_SALARY
---------- ------------
10 8750
20 10875
30 9400
解説:
行がバラバラだったデータが、部署コードごとに1行にまとめられ、その中の SAL が合算されました。
パターン2:HAVING の追加(給与合計が高い部署のみ抽出)
「給与合計が 9,000 を超える部署だけ知りたい」という場合、HAVING を追加します。
SELECT
DEPTNO,
SUM(SAL) AS TOTAL_SALARY
FROM EMP
GROUP BY DEPTNO
HAVING SUM(SAL) > 9000
ORDER BY DEPTNO;
実行結果:
SQL> SELECT
2 DEPTNO,
3 SUM(SAL) AS TOTAL_SALARY
4 FROM EMP
5 GROUP BY DEPTNO
6 HAVING SUM(SAL) > 9000
7 ORDER BY DEPTNO;
DEPTNO TOTAL_SALARY
---------- ------------
20 10875
30 9400
解説:
合計が 8750 だった「DEPTNO 10」が集計後のフィルタリングで除外されました。
パターン3:WHERE と HAVING の併用(応用)
最も実務に近い形です。
「職種が ‘CLERK’ (事務員) の社員だけで集計し、その中で平均給与が 1000 以上の部署を表示する」
SELECT
DEPTNO,
COUNT(*) AS MEMBER_COUNT,
AVG(SAL) AS AVG_SAL
FROM EMP
WHERE JOB = 'CLERK' -- 1. まずCLERKだけに絞る
GROUP BY DEPTNO -- 2. 部署ごとにまとめる
HAVING AVG(SAL) >= 1000; -- 3. 平均1000以上を残す
実行結果:
SQL> SELECT
2 DEPTNO,
3 COUNT(*) AS MEMBER_COUNT,
4 AVG(SAL) AS AVG_SAL
5 FROM EMP
6 WHERE JOB = 'CLERK'
7 GROUP BY DEPTNO
8 HAVING AVG(SAL) >= 1000;
DEPTNO MEMBER_COUNT AVG_SAL
---------- ------------ ----------
10 1 1300
解説:
WHERE: 全社員からCLERKだけを抽出します。GROUP BY: 残ったCLERKを部署ごとに分けます。HAVING: そのグループの平均給与を判定します。
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?
4. トラブルシューティング:よくあるエラー
集計クエリで頻発する ORA エラーとその対処法です。
| エラーコード | メッセージ | 原因と対処 |
| ORA-00934 | グループ関数はここでは使用できません | 原因: WHERE 句で集計関数(SUM, AVG等)を使っています。対処: 集計結果に対する条件は HAVING 句に移動してください。 |
| ORA-00979 | GROUP BYの式ではありません | 原因: SELECT リストにある列が GROUP BY に含まれていません。対処: 集計関数を使っていない列は、すべて GROUP BY 句に記述する必要があります。 |
NG例(ORA-00934):
-- 間違い:集計結果をWHEREで判定しようとしている
SELECT DEPTNO, SUM(SAL)
FROM EMP
WHERE SUM(SAL) > 9000
GROUP BY DEPTNO;
実行結果:
SQL> SELECT DEPTNO, SUM(SAL)
2 FROM EMP
3 WHERE SUM(SAL) > 9000
4 GROUP BY DEPTNO;
WHERE SUM(SAL) > 9000
*
ERROR at line 3:
ORA-00934: group function is not allowed here
5. 運用・監視・セキュリティ上の注意
パフォーマンスへの影響
GROUP BY は内部的にデータのソート(並べ替え)やハッシュ処理を行うため、データ量が多いと負荷が高くなります。
- ベストプラクティス: 可能な限り
WHERE句で事前にデータを絞り込んで からGROUP BYしてください。集計対象の行数を減らすことが、最良のチューニングです。
NULLの扱い
GROUP BY 列に NULL が含まれる場合、Oracle では NULL も1つのグループ としてまとめられます。意図しない場合は WHERE 列名 IS NOT NULL で除外してください。
6. FAQ:よくある質問
Q1. SELECT句に書いていない列で GROUP BY できますか?
A. はい、可能です。ただし、結果にはその列が表示されないため、どのグループの集計結果なのか判別できなくなる可能性があります。通常は SELECT 句と GROUP BY 句の列を一致させます。
Q2. HAVING 句で別名(エイリアス)は使えますか?
A. Oracle Database 19c 時点では、標準設定において GROUP BY や HAVING 句で SELECT 句で定義した別名(AS 〇〇)を直接使用することはできません(ORA-00904 エラーになります)。式をそのまま書くか、サブクエリを使用してください。
Q3. 複数の列でグループ化できますか?
A. はい、カンマ区切りで複数指定できます。
例: GROUP BY DEPTNO, JOB
これにより「部署かつ職種」ごとの細かいグループで集計されます。
まとめ
- 役割分担: 集計前の絞り込みは
WHERE、集計後の絞り込みはHAVING。 - 構文順序:
WHERE→GROUP BY→HAVINGの順で書く(そして実行される)。 - エラー回避:
SELECTにある列はGROUP BYにも書く(集計関数以外)。 - 実機練習: まずは
GROUP BYだけで実行し、結果を見てからHAVINGを足すと理解しやすい。
本記事は Oracle Database 19c を対象に解説します(他バージョンは画面や既定値が異なる場合があります)。
[参考]
Oracle Database SQL言語リファレンス 19c
💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?
Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?




コメント