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;
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;
ORDER BY句との組み合わせ
GROUP BY と ORDER BY を組み合わせる場合、ORDER BY には GROUP BY に指定した列か集計関数のみ指定できる。
-- 部門ごとの平均給与を高い順に並べる
SELECT deptno, AVG(sal)
FROM emp
GROUP BY deptno
ORDER BY AVG(sal) DESC;
HAVING句とは
HAVING 句は、GROUP BY でグループ化・集計した結果に対して絞り込み条件を指定するための句。
WHERE 句が「行単位のフィルタ(グループ化前)」なのに対し、HAVING 句は「グループ単位のフィルタ(グループ化後)」という役割を持つ。
-- 部門ごとの給与合計が 10000 を超える部門のみ表示
SELECT deptno, SUM(sal)
FROM emp
GROUP BY deptno
HAVING SUM(sal) > 10000;
WHERE句と HAVING句の使い分け
| 比較項目 | WHERE句 | HAVING句 |
|---|---|---|
| 適用タイミング | グループ化の前 | グループ化の後 |
| 絞り込み対象 | 個々の行 | グループ(集計結果) |
| 集計関数の使用 | ❌ 使えない | ✅ 使える |
| 記述できる条件 | 列の値に対する条件 | 集計関数を含む条件 |
| 参考 |
パフォーマンスの観点:行単位で絞り込める条件は
WHEREを使うほうがよい。WHEREで先に行数を減らしてからGROUP BYすると、処理対象データが減り効率的。
集計ファンクションのネスト
ネストとは
集計ファンクションの引数に、別の集計ファンクションを入れることを「ネスト(入れ子)」という。たとえば「部門ごとの合計給与の最大値」を1回のクエリで求める場合に使用する。
-- 部門ごとの合計給与(SUM)のうち、最大値(MAX)を求める
SELECT MAX(SUM(sal))
FROM emp
GROUP BY deptno;
ネストのルール
元の記事には「戻される行数は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 はこれをエラーとして扱う。
試験で意識したいポイントまとめ
| ポイント | 内容 |
|---|---|
| 「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 エラー |






