ORA-00937: not a single-group group function は、Oracleで SUM、COUNT、AVG、MAX、MIN などの集計関数と、通常の列を GROUP BY なしで同じ SELECT 句に書いたときに発生するエラーです。
たとえば「部署ID」と「全体の売上合計」を同時に出そうとして、SELECT department_id, SUM(amount) FROM sales のように書くと、Oracleは department_id をどの単位で1行にまとめればよいか判断できません。
ORA-00937は、通常列を表示したいなら
GROUP BY を追加し、全体集計だけが欲しいなら通常列をSELECTから外すと直ります。明細行を残したまま集計値も出したい場合は、SUM(...) OVER (...) のような分析関数を使います。ORA-00937とは
Oracle公式の説明では、ORA-00937は、AVG、COUNT、MAX、MIN、SUM、STDDEV、VARIANCE などのグループ関数と、個別の列式を同じSELECTリストに含めたのに、その個別列が GROUP BY 句に含まれていない場合に発生します。
ポイントは「集計結果は1行にまとまるのに、通常列は複数行ぶん存在する」ことです。SQLとして、全体で1行にしたいのか、部署ごと・顧客ごと・月ごとに複数行へ分けたいのかを明示する必要があります。
| やりたいこと | 正しい考え方 | 使う構文 |
|---|---|---|
| 全体の合計だけ出す | 通常列を表示しない | SELECT SUM(amount) |
| 部署ごとの合計を出す | 部署IDでグループ化する | GROUP BY department_id |
| 明細行に部署合計も付ける | 行をまとめず分析関数を使う | SUM(...) OVER (PARTITION BY ...) |
| 集計結果とマスタ名を出す | 先に集計してからJOINする | サブクエリ / WITH |
もっとも多い原因:集計関数と通常列を混ぜている
典型例は、通常列と集計関数を同時にSELECTしているのに、GROUP BYを書いていないパターンです。
-- NG: department_id は通常列、SUM(amount) は集計関数
SELECT department_id,
SUM(amount) AS total_amount
FROM sales;
部署ごとの合計が欲しいなら、部署IDを GROUP BY に入れます。
-- OK: department_id ごとに集計する
SELECT department_id,
SUM(amount) AS total_amount
FROM sales
GROUP BY department_id;
GROUP BYの基本は SQLのGROUP BYで件数をカウントする方法、合計の考え方は SUM関数の使い方 が参考になります。
全体集計だけが欲しいなら通常列を外す
部署別ではなく、テーブル全体の合計や件数だけが欲しい場合、通常列をSELECTから外します。GROUP BYを足すと結果が部署ごとに分かれてしまうため、欲しい結果が変わります。
-- OK: 全体で1行の集計結果だけを返す
SELECT COUNT(*) AS sales_count,
SUM(amount) AS total_amount,
AVG(amount) AS avg_amount
FROM sales
WHERE order_date >= DATE '2026-01-01';
全体集計では、GROUP BY を書かなくてもテーブル全体が1つのグループとして扱われます。そのため、SELECTできるのは定数、集計関数、集計式などに限られます。件数は COUNT関数、平均は AVG関数 も確認してください。
GROUP BYを足すと集計粒度が変わる
ORA-00937を直すために GROUP BY を追加するのはよくある修正ですが、集計単位が変わる点に注意します。全体で1行だった集計が、部署ごと、顧客ごと、日付ごとに複数行へ分かれます。
-- 全体で1行
SELECT SUM(amount) AS total_amount
FROM sales;
-- 部署ごとに複数行
SELECT department_id,
SUM(amount) AS total_amount
FROM sales
GROUP BY department_id;
SQLが通るかどうかだけでなく、「何ごとの合計なのか」を先に決めます。集計粒度を変えたくないなら、通常列を外すか、サブクエリや分析関数に分けます。
COUNTと通常列を混ぜたケース
COUNT は特にORA-00937を起こしやすい集計関数です。一覧画面で「部署名と件数」を出したいときに、GROUP BYを書き忘れるパターンがよくあります。
-- NG: department_name と COUNT(*) を混ぜているが GROUP BY がない
SELECT department_name,
COUNT(*) AS employee_count
FROM employees;
-- OK: 部署名ごとに件数を数える
SELECT department_name,
COUNT(*) AS employee_count
FROM employees
GROUP BY department_name;
MAX/MINと通常列を混ぜたケース
MAX や MIN でも同じです。「最終注文日と顧客名」を出したい場合、単に MAX(order_date) と customer_name を並べるだけでは、どの顧客名を表示すべきか決まりません。
-- NG: customer_name が集計単位として決まらない
SELECT customer_name,
MAX(order_date) AS latest_order_date
FROM orders;
-- OK: 顧客ごとの最終注文日
SELECT customer_name,
MAX(order_date) AS latest_order_date
FROM orders
GROUP BY customer_name;
「全体で最も新しい注文の顧客名」を取りたいなら、GROUP BYではなくサブクエリや分析関数で該当行を取り出します。この違いを混同すると、SQLは通っても欲しい結果と違う集計になります。
-- 全体で最も新しい注文の行を取りたい場合
SELECT customer_name,
order_date
FROM orders
WHERE order_date = (
SELECT MAX(order_date)
FROM orders
);
-- 同日の行が複数ある場合は複数行返る
1行だけに絞りたい場合は、ROW_NUMBER() を使って並び順を明示します。MAX値と一緒に他の列を出したいケースでは、単純なGROUP BYよりこの形のほうが意図を保ちやすいです。
SELECT customer_name,
order_date,
amount
FROM (
SELECT customer_name,
order_date,
amount,
ROW_NUMBER() OVER (ORDER BY order_date DESC, order_id DESC) AS rn
FROM orders
)
WHERE rn = 1;
明細行も集計値も出したいなら分析関数を使う
明細行を残したまま、同じ行に合計や件数を付けたい場合は、通常の集計関数ではなく分析関数を使います。分析関数は行をまとめず、各行に集計値を付加できます。
-- 明細行を残しながら部署ごとの合計を表示する
SELECT employee_id,
department_id,
amount,
SUM(amount) OVER (PARTITION BY department_id) AS department_total
FROM sales;
分析関数の詳しい使い方は Oracleの分析関数の使い方 にまとめています。GROUP BYは行をまとめる、分析関数は行を残す、と分けて考えると選びやすくなります。
全行に全体件数や部署内件数を付けたい場合も、COUNT(*) OVER が使えます。一覧画面で「明細 + 総件数」や「明細 + 部署内件数」を表示したいときに便利です。
SELECT employee_id,
department_id,
employee_name,
COUNT(*) OVER () AS all_employee_count,
COUNT(*) OVER (PARTITION BY department_id) AS department_employee_count
FROM employees;
サブクエリに分けると直しやすいケース
集計結果とマスタ列を一緒に表示したい場合は、先に集計してからJOINすると読みやすくなります。集計対象の列と表示用の列を分けられるため、ORA-00937を避けやすくなります。
WITH sales_summary AS (
SELECT department_id,
SUM(amount) AS total_amount
FROM sales
GROUP BY department_id
)
SELECT d.department_id,
d.department_name,
s.total_amount
FROM departments d
JOIN sales_summary s
ON s.department_id = d.department_id;
CASE式と集計関数で発生するケース
条件付き集計で CASE と集計関数を混ぜる場合も注意します。行単位の列をSELECTに残したまま集計関数を書くとORA-00937になります。
-- OK: CASE式をSUMの中に入れて、全体で1行の条件付き集計にする
SELECT SUM(CASE WHEN status = 'PAID' THEN amount ELSE 0 END) AS paid_amount,
SUM(CASE WHEN status = 'UNPAID' THEN amount ELSE 0 END) AS unpaid_amount
FROM invoices;
-- OK: 顧客ごとに条件付き集計するならGROUP BYを追加する
SELECT customer_id,
SUM(CASE WHEN status = 'PAID' THEN amount ELSE 0 END) AS paid_amount
FROM invoices
GROUP BY customer_id;
CASE式の条件集計は OracleのCASE式 でも詳しく扱っています。
DISTINCTではORA-00937の根本解決にならない
ORA-00937が出たとき、DISTINCT を付ければ重複が消えて直るのでは、と考えることがあります。しかし、DISTINCT は結果行の重複を除くための機能で、集計関数と通常列を同時にSELECTするルールを変えるものではありません。
-- NG: DISTINCT を付けても、通常列と集計関数の混在は解決しない
SELECT DISTINCT department_id,
SUM(amount) AS total_amount
FROM sales;
-- OK: department_id ごとの集計ならGROUP BYを書く
SELECT department_id,
SUM(amount) AS total_amount
FROM sales
GROUP BY department_id;
重複を消したいのか、集計したいのかを分けて考えます。重複排除が目的ならDISTINCT、集計が目的ならGROUP BYや集計関数を使います。
ORA-00979との違い
ORA-00937とORA-00979はどちらも集計とGROUP BYに関係するため混同しやすいです。ざっくり言うと、ORA-00937は「GROUP BYがないのに集計関数と通常列を混ぜた」、ORA-00979は「GROUP BYはあるが、GROUP BYに含まれない列や式が残っている」エラーです。
| エラー | 典型パターン | 直し方 |
|---|---|---|
ORA-00937 |
SELECT dept, SUM(amount) FROM sales |
GROUP BY dept を足す、または dept を外す |
ORA-00979 |
SELECT dept, name, SUM(amount) FROM sales GROUP BY dept |
name をGROUP BYへ入れる、または集計/削除する |
GROUP BY句がないならまずORA-00937、GROUP BY句があるのに列が足りないなら ORA-00979の原因と解決方法 を確認してください。
直し方の判断フロー
| 質問 | YESの場合 | NOの場合 |
|---|---|---|
| 全体で1行の集計が欲しい? | 通常列をSELECTから外す | 次へ |
| 列ごと・部署ごと・月ごとに集計したい? | GROUP BY を追加する |
次へ |
| 明細行を残したい? | 分析関数を使う | サブクエリで集計してJOINする |
| マスタ名など表示用の列が必要? | 先に集計してからJOINする | 集計SQLをシンプルにする |
修正チェックリスト
| 手順 | 確認すること | 判断 |
|---|---|---|
| 1 | SELECT 句に集計関数があるか |
SUM、COUNT、AVG など |
| 2 | 同じSELECT句に通常列があるか | department_id、customer_name など |
| 3 | GROUP BY があるか |
なければORA-00937の典型 |
| 4 | 欲しい結果が全体1行か複数行か | 全体1行なら通常列を外す |
| 5 | 集計単位が決まっているか | 部署ごとなら GROUP BY department_id |
| 6 | 明細行を残したいか | 残すなら分析関数を検討する |
| 7 | SQLが複雑すぎないか | サブクエリやWITH句に分ける |
よくある質問
GROUP BYを付ければ必ず直りますか?
SQLエラーは直ることがありますが、集計粒度が変わるため、必ず正しい結果になるとは限りません。全体集計が欲しいなら通常列を外し、部署別や顧客別にしたいならGROUP BYを追加します。
COUNT(*)と通常列を一緒に出したい場合はどうしますか?
通常列ごとの件数が欲しいなら、その通常列をGROUP BYに入れます。明細行に全体件数を付けたいなら COUNT(*) OVER () のような分析関数を使います。
MAX値の行の他の列も表示したい場合は?
MAX と通常列をただ並べるのではなく、サブクエリでMAX値を求めて該当行をJOINするか、ROW_NUMBER() などの分析関数で1行を選びます。
DISTINCTを付ければ直りますか?
基本的には直し方として適切ではありません。DISTINCT は重複行を除く機能で、集計関数と通常列の混在ルールを解決するものではありません。
ORA-00937とORA-00979のどちらを見ればよいですか?
GROUP BY句がないならORA-00937、GROUP BY句があるのにSELECTやORDER BYに未グループ化列が残っているならORA-00979を疑います。
まとめ
ORA-00937は、GROUP BYなしで集計関数と通常列を同じSELECT句に書いたときに発生します。まず、欲しい結果が全体で1行なのか、部署ごと・顧客ごとなど複数行なのかを決めます。
全体集計なら通常列を外し、グループ別集計ならGROUP BYを追加します。明細行を残したい場合は、通常の集計ではなく分析関数やサブクエリを使うと安全です。ORA-00979との違いも押さえると、集計SQLのエラーをかなり速く切り分けられます。
