0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Oracle Database SQL (1Z0-071-JPN)試験 GROUP BY句 HAVING句【第6章_後編】

0
Last updated at Posted at 2026-04-05

GROUP BY句とは

GROUP BY句は、指定した列の値が同じデータをひとまとめにし、グループ単位で集計処理を行うための句。グループごとに SUM・AVG・COUNT などの集計関数を適用でき、グループごとに1行の集計結果が返される。

基本構文

SELECT   列名, 集計関数(列名)
FROM     テーブル名
WHERE    集計前の絞り込み条件        -- 省略可
GROUP BY グループ化したい列名
HAVING   集計後の絞り込み条件        -- 省略可
ORDER BY 並び替え;                   -- 省略可

SQL の実行(評価)順序

SQL の構文を記述する順番と、実際に実行(評価)される順番は異なる。

評価順 句 処理内容
1 FROM 対象テーブルを読み込む
2 WHERE 行単位でフィルタリング(グループ化の前)
3 GROUP BY 行をグループにまとめる
4 HAVING グループ単位でフィルタリング(グループ化の後)
5 SELECT 出力する列・式を確定する
6 ORDER BY 結果を並び替える

試験ポイント:WHERE はグループ化の前、HAVING はグループ化の後に評価される。この順序を意識すると「なぜ WHERE で集計関数を使えないのか」が理解しやすい。


GROUP BY句のポイント

複数列によるグループ化

GROUP BY に複数の列を指定すると、その列の組み合わせ単位でグループ分けされる。

-- 部門 × 職種の組み合わせでグループ化
SELECT   deptno, job, SUM(sal)
FROM     emp
GROUP BY deptno, job;
動作確認

■テストデータ

DROP TABLE dept PURGE;
DROP TABLE emp PURGE;


-- 部門テーブル
CREATE TABLE dept (
    deptno   NUMBER(2)    PRIMARY KEY,
    dname    VARCHAR2(14),
    loc      VARCHAR2(13)
);

-- 社員テーブル
CREATE TABLE emp (
    empno    NUMBER(4)    PRIMARY KEY,
    ename    VARCHAR2(10),
    job      VARCHAR2(9),
    mgr      NUMBER(4),
    hiredate DATE,
    sal      NUMBER(7,2),
    comm     NUMBER(7,2),
    deptno   NUMBER(2)    REFERENCES dept(deptno)
);

INSERT INTO dept (deptno, dname, loc) VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO dept (deptno, dname, loc) VALUES (20, 'RESEARCH',   'DALLAS');
INSERT INTO dept (deptno, dname, loc) VALUES (30, 'SALES',      'CHICAGO');
INSERT INTO dept (deptno, dname, loc) VALUES (40, 'OPERATIONS', 'BOSTON');

-- deptno = 10 (ACCOUNTING)
INSERT INTO emp VALUES (1001, 'SMITH',  'CLERK',     1100, DATE '2020-01-15', 1200,   NULL, 10);
INSERT INTO emp VALUES (1002, 'ALLEN',  'SALESMAN',  1100, DATE '2019-03-10', 1600,   300,  10);
INSERT INTO emp VALUES (1003, 'WARD',   'SALESMAN',  1100, DATE '2018-07-20', 1250,   500,  10);

-- deptno = 20 (RESEARCH)
INSERT INTO emp VALUES (2001, 'JONES',  'MANAGER',   1100, DATE '2017-04-02', 2975,   NULL, 20);
INSERT INTO emp VALUES (2002, 'SCOTT',  'ANALYST',   2001, DATE '2021-12-09', 3000,   NULL, 20);
INSERT INTO emp VALUES (2003, 'ADAMS',  'CLERK',     2002, DATE '2022-01-12', 1100,   NULL, 20);
INSERT INTO emp VALUES (2004, 'FORD',   'ANALYST',   2001, DATE '2019-06-25', 3000,   NULL, 20);

-- deptno = 30 (SALES)
INSERT INTO emp VALUES (3001, 'MARTIN','SALESMAN',   1100, DATE '2020-09-28', 1250,  1400, 30);
INSERT INTO emp VALUES (3002, 'BLAKE', 'MANAGER',    1100, DATE '2015-05-01', 2850,   NULL, 30);
INSERT INTO emp VALUES (3003, 'TURNER','SALESMAN',   3002, DATE '2019-09-08', 1500,     0, 30);
INSERT INTO emp VALUES (3004, 'JAMES', 'CLERK',      3002, DATE '2021-12-03',  950,   NULL, 30);

-- deptno = 40 (OPERATIONS)
INSERT INTO emp VALUES (4001, 'MILLER','CLERK',      2001, DATE '2020-01-23', 1300,   NULL, 40);
INSERT INTO emp VALUES (4002, 'CLARK', 'MANAGER',    1100, DATE '2016-06-09', 2450,   NULL, 40);
COMMIT;

■実行結果
image.png

SELECT句と GROUP BY句の関係

GROUP BY を使う場合、SELECT 句に書ける列は次の2つのみ。

  • GROUP BY に指定した列
  • 集計関数(SUM・AVG・COUNT など)

注意:GROUP BY に指定していない列を SELECT に書くと ORA-00979: not a GROUP BY expression エラーになる。

WHERE句との組み合わせ

WHERE 句はグループ化の前に評価されるため、特定の行を除外してからグループ集計を行える。

-- 給与が 1000 以上の社員のみを対象に部門ごとの合計給与を集計
SELECT   deptno, SUM(sal)
FROM     emp
WHERE    sal >= 1000
GROUP BY deptno;
動作確認

■実行結果
image.png

ORDER BY句との組み合わせ

GROUP BY と ORDER BY を組み合わせる場合、ORDER BY には GROUP BY に指定した列か集計関数のみ指定できる。

-- 部門ごとの平均給与を高い順に並べる
SELECT   deptno, AVG(sal)
FROM     emp
GROUP BY deptno
ORDER BY AVG(sal) DESC;
動作確認

■実行結果
image.png


HAVING句とは

HAVING 句は、GROUP BY でグループ化・集計した結果に対して絞り込み条件を指定するための句。
WHERE 句が「行単位のフィルタ(グループ化前)」なのに対し、HAVING 句は「グループ単位のフィルタ(グループ化後)」という役割を持つ。

-- 部門ごとの給与合計が 10000 を超える部門のみ表示
SELECT   deptno, SUM(sal)
FROM     emp
GROUP BY deptno
HAVING   SUM(sal) > 10000;
動作確認

■実行結果
image.png

WHERE句と HAVING句の使い分け

比較項目 WHERE句 HAVING句
適用タイミング グループ化の前 グループ化の後
絞り込み対象 個々の行 グループ(集計結果)
集計関数の使用 ❌ 使えない ✅ 使える
記述できる条件 列の値に対する条件 集計関数を含む条件
参考

パフォーマンスの観点:行単位で絞り込める条件は WHERE を使うほうがよい。WHERE で先に行数を減らしてから GROUP BY すると、処理対象データが減り効率的。


集計ファンクションのネスト

ネストとは

集計ファンクションの引数に、別の集計ファンクションを入れることを「ネスト(入れ子)」という。たとえば「部門ごとの合計給与の最大値」を1回のクエリで求める場合に使用する。

-- 部門ごとの合計給与(SUM)のうち、最大値(MAX)を求める
SELECT MAX(SUM(sal))
FROM   emp
GROUP BY deptno;
動作確認

■実行結果
image.png

ネストのルール

元の記事には「戻される行数は1行になり」「GROUP BY句が必要」という記述があるが、正確には以下の2点を補足する必要がある。

① ネストは SELECT句でのみ使用できる
集計ファンクションのネストは SELECT 句の中に限り有効。HAVING 句など他の句ではネスト自体はできても、結果が1行に集約されるためほとんどのケースで意味をなさない。

② GROUP BY句が必須
GROUP BY 句なしで集計ファンクションをネストした場合、全行が1グループとして扱われるため「グループ化なしの再集計」になる。例として MAX(SUM(sal)) を実行するには GROUP BY でグループを作る必要がある。

③ ネストは2レベルまで(3レベル以上はエラー)
Oracle SQL では集計ファンクションのネストは 2階層まで。3階層以上ネストすると ORA-00935: グループ関数のネスト・レベルが深すぎます エラーになる。

-- ✅ 2レベルのネスト(正常)
SELECT MAX(SUM(sal))
FROM   emp
GROUP BY deptno;

-- ❌ 3レベルのネスト(ORA-00935 エラー)
SELECT COUNT(MAX(AVG(sal)))
FROM   emp
GROUP BY deptno;

なぜ3レベルが不可か:2階層目の集計結果は1行しか返らない。1行のデータをさらにグループ集計することは意味がなく、Oracle はこれをエラーとして扱う。

動作確認

■実行結果
ネストレベル2
image.png

ネストレベル3
image.png


試験で意識したいポイントまとめ

ポイント 内容
「GROUP句」という用語 正しくは「GROUP BY句」
SQL の評価順序 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
GROUP BY と SELECT の関係 SELECT には GROUP BY 列か集計関数しか書けない
WHERE と HAVING の使い分け WHERE は行単位(集計前)、HAVING はグループ単位(集計後)
ORDER BY と GROUP BY の組み合わせ ORDER BY には GROUP BY 列か集計関数のみ指定可
ネストは SELECT 句のみ HAVING 句でのネストは基本的に意味をなさない
ネストは GROUP BY 必須 GROUP BY なしでは全体が1グループになる
ネストの上限は2レベル 3レベル以上は ORA-00935 エラー

参考一覧

  1. グループ関数とデータの集計 #SQL

  2. SQLリファレンス・ガイド

  3. Oracle SQL GROUP BYとHAVINGの使い方!集計と条件指定

  4. where句とhaving句の実行順番の違い - けむブログ

  5. SQLの処理順序を理解してクエリを書こう - アユダンテ株式会社

  6. Order By句でグループ関数を使う - こじりふぁ

  7. SQLの基礎:WHEREとHAVINGの使い分けについて - Qiita

  8. 【SQL】HAVINGの使い方とWHEREとの違いを解説 - テックマニア

  9. [SQL] 検索結果のグループ化を行う(GROUP BY)

  10. SQLのHAVING句の使い方 | PostgreSQL, SQLServer, MySQL, Oracle ...

  11. 【Oracle】HAVING でグループ化して条件を指定する

  12. Oracle SQL WHEREとHAVINGの違い!実行順序と使い分け

  13. Oracle SQL 集計の応用!GROUP BY結果の再集計とROLLUP

  14. SQL関数振り返り ~ 文字列関数・日付関数・数値関数・変換関数・条件式・グループ関数

  15. 2024/02/14学習記録(SQL:ping-t/グループ関数)途中|しえろ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?