- データベース
must appear in the GROUP BY clauseの直し方
ERROR: column "c.name" must appear in the GROUP BY clause or be used in an aggregate function は、GROUP BY で集計するときに、グループごとに1つに決まらない列を SELECT・ORDER BY・HAVING に書いたときのエラーです。 エラー文の "c.name" が問題の列で、^ がその位置を指します。
エラー文のとおり、その列を GROUP BY に入れるか、集計関数で包むかですが、どちらが正しいかは「何を出したいか」で決まります。
| やりたいこと | 書き方 |
|---|---|
| 顧客ごとに集計して、顧客の名前も出す | 主キー(c.id)で GROUP BY(名前は GROUP BY に書かなくてよい) |
| グループごとの最新の1行 | DISTINCT ON または ROW_NUMBER() |
| グループの値を並べる | string_agg(DISTINCT 列, ',') |
| グループの合計を各行に添える | ウィンドウ関数 SUM(...) OVER (PARTITION BY ...) |
確認環境:PostgreSQL 16.15(確認日 2026年10月11日)。MySQL のエラー(1055)の記事と同じデータで再現しました。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「must appear in the GROUP BY clauseの直し方」
再現
customers(主キー id) orders2
id name pref id customer_id amount ordered_at
1 佐藤 東京 1 1 1000 2026-10-01
2 鈴木 大阪 2 1 3000 2026-10-05
3 高橋 東京 3 2 2000 2026-10-02
4 3 500 2026-10-03
5 3 800 2026-10-09
SELECT pref, name, SUM(o.amount) FROM customers c JOIN orders2 o ON o.customer_id = c.id GROUP BY pref;
ERROR: column "c.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT pref, name, SUM(o.amount) FROM customers c JOIN order...
^
「東京」には佐藤と高橋がいるので、name を1つに決められません。MySQL のように「どれか1つ」を返す設定はなく、PostgreSQL では常にエラーになります。
直し方1:主キーで GROUP BY する
SELECT c.id, c.name, c.pref, SUM(o.amount) AS total
FROM customers c JOIN orders2 o ON o.customer_id = c.id
GROUP BY c.id;
id | name | pref | total
----+------+------+-------
1 | 佐藤 | 東京 | 4000
2 | 鈴木 | 大阪 | 2000
3 | 高橋 | 東京 | 1300
GROUP BY にテーブルの主キーを入れると、同じテーブルのほかの列(name・pref)は書かなくても通りました。 主キーが決まれば、ほかの列も1つに決まるためです(PostgreSQL 公式ドキュメントの「関数従属」)。
主キーが無いテーブルでは通らない
(同じデータで、id が主キーではないテーブル customers_nopk)
SELECT c.id, c.name, SUM(o.amount) FROM customers_nopk c JOIN ... GROUP BY c.id;
ERROR: column "c.name" must appear in the GROUP BY clause or be used in an aggregate function
id の値が実際には重複していなくても、主キーが定義されていないとエラーになりました。 公式ドキュメントでも、関数従属を認めるのは「GROUP BY に、そのテーブルの主キーが含まれるとき」だけとされています。UNIQUE 制約だけの列も、この扱いの対象外です。その場合は、GROUP BY c.id, c.name のように列を並べます。
直し方2:グループごとの最新の1行(DISTINCT ON)
SELECT customer_id, MAX(ordered_at), amount FROM orders2 GROUP BY customer_id;
ERROR: column "orders2.amount" must appear in the GROUP BY clause or be used in an aggregate function
「最新の注文の金額」は、GROUP BY では書けません。PostgreSQL の DISTINCT ON を使います。
SELECT DISTINCT ON (customer_id) customer_id, ordered_at, amount
FROM orders2
ORDER BY customer_id, ordered_at DESC;
customer_id | ordered_at | amount
-------------+---------------------+--------
1 | 2026-10-05 00:00:00 | 3000
2 | 2026-10-02 00:00:00 | 2000
3 | 2026-10-09 00:00:00 | 800
DISTINCT ON (列) は、その列が同じ行のうち、ORDER BY で先頭に来た1行だけを残します。 公式ドキュメントのとおり、DISTINCT ON の列を ORDER BY の先頭に書き、その後ろに「どの行を先にするか」(ordered_at DESC)を書きます。ORDER BY が無いと、どの行が残るかは決まりません。
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY ordered_at DESC) で番号を付けて 1 番を取る方法でも、同じ結果になります(MySQL など他の DB でも使える書き方)。
直し方3:グループの値を並べる・どれか1つ
SELECT pref, string_agg(DISTINCT name, ',' ORDER BY name) AS names, SUM(o.amount) AS total
FROM customers c JOIN orders2 o ON o.customer_id = c.id
GROUP BY pref;
pref | names | total
------+-----------+-------
大阪 | 鈴木 | 2000
東京 | 佐藤,高橋 | 5300
JOIN した結果を集計しているので、DISTINCT が無いと「佐藤,佐藤,高橋,高橋」のように注文の数だけ重なりました。
| 関数 | 結果 |
|---|---|
string_agg(DISTINCT 列, ',' ORDER BY 列) |
値を並べる |
any_value(列) |
どれか1つ(確認環境の PostgreSQL 16 で使えた) |
max(列)・min(列) |
最大・最小 |
any_value は MySQL の ANY_VALUE と同じく「どれか1つ」です。グループの中で値が同じだと分かっている列にだけ使います。
直し方4:合計を各行に添える(ウィンドウ関数)
「顧客ごとの合計」と「都道府県ごとの合計」を同じ行に出したいときは、GROUP BY ではなくウィンドウ関数を使います。
SELECT c.name, c.pref, t.total,
SUM(t.total) OVER (PARTITION BY c.pref) AS pref_total
FROM customers c
JOIN (SELECT customer_id, SUM(amount) AS total FROM orders2 GROUP BY customer_id) t
ON t.customer_id = c.id;
name | pref | total | pref_total
------+------+-------+------------
鈴木 | 大阪 | 2000 | 2000
佐藤 | 東京 | 4000 | 5300
高橋 | 東京 | 1300 | 5300
ORDER BY・HAVING でも出る
... GROUP BY pref ORDER BY c.name;
ERROR: column "c.name" must appear in the GROUP BY clause or be used in an aggregate function
SELECT pref FROM customers GROUP BY pref HAVING name = '佐藤';
ERROR: column "customers.name" must appear in the GROUP BY clause or be used in an aggregate function
HAVING の条件は、集計のあとに使われるので、集計していない列は使えません。行を絞る条件なら WHERE に書きます。
MySQL から移すときの違い
| SQL | MySQL 8.0(既定) | MySQL(ONLY_FULL_GROUP_BY を外した) | PostgreSQL |
|---|---|---|---|
GROUP BY pref で name を SELECT |
ERROR 1055 | どれか1つを返す | エラー |
| 主キーで GROUP BY、他の列を SELECT | 通る | 通る | 通る |
ANY_VALUE(name) |
通る | 通る | any_value(name) で通る |
| 最新の1行 | ROW_NUMBER() |
〃 | DISTINCT ON または ROW_NUMBER() |
MySQL で sql_mode を緩めて動かしていた SQL は、PostgreSQL ではそのままでは動きません。 移す前に、上の書き方に直します。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | 問題の列 | エラー文の column "..." と ^ の位置 |
| 2 | 何ごとに集計したいか | 主キーごとなら、主キーで GROUP BY |
| 3 | 主キーが定義されているか | \d テーブル名。無ければ列を GROUP BY に並べる |
| 4 | 最新の1行が欲しいか | DISTINCT ON(ORDER BY の先頭をそろえる) |
| 5 | 値を並べる・どれか1つ | string_agg(DISTINCT ...)、any_value |
| 6 | HAVING に書いていないか | 行の条件は WHERE に |
よくある質問
Q. SQLSTATE は何ですか。
A. 42803(grouping_error)です。
Q. GROUP BY に列を全部書けば直りますか。 A. エラーは消えますが、グループの単位が変わり、結果の意味が変わります(都道府県ごとのつもりが、都道府県×名前ごとになる)。何ごとに集計したいかを決めてから直します。
まとめ
- グループごとに1つに決まらない列を書いたエラー。PostgreSQL では常にエラー
- 主キーで GROUP BY すれば、同じテーブルの他の列は書ける。主キーが無いと通らない
- 最新の1行は
DISTINCT ON(ORDER BY の先頭に同じ列) - 並べるなら
string_agg(DISTINCT ...)。JOIN 後は重複に注意 - HAVING の条件は集計後。行の条件は WHERE
- MySQL で sql_mode を緩めていた SQL は、移す前に直す
参考・出典
確認日はいずれも 2026年10月11日です。
- PostgreSQL 16 Documentation「SELECT」(GROUP BY Clause・DISTINCT Clause):https://www.postgresql.org/docs/16/sql-select.html
- PostgreSQL 16 Documentation「Aggregate Functions」:https://www.postgresql.org/docs/16/functions-aggregate.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「must appear in the GROUP BY clauseの直し方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。