- データベース
column reference is ambiguousの直し方|SQL
ERROR: column reference "id" is ambiguous は、JOIN した2つ以上のテーブルに同じ名前の列があり、どのテーブルの列かを書かなかったときのエラーです。 MySQL では ERROR 1052 (23000): Column 'id' in field list is ambiguous になります。
直し方は、列名の前にテーブル名(または別名)を付けることです。
-- エラー
SELECT id, name, amount FROM amb_c c JOIN amb_o o ON o.customer_id = c.id;
-- 直したもの
SELECT c.id, c.name, o.amount FROM amb_c c JOIN amb_o o ON o.customer_id = c.id;
ただし、PL/pgSQL の関数では、テーブルどうしではなく 関数の引数・戻り値の列名と、テーブルの列名がぶつかって、このエラーになります。下で詳しく説明します。
確認環境:PostgreSQL 16.15、MySQL 8.0.46(確認日 2026年10月11日)。顧客(amb_c:id・name・created_at)と注文(amb_o:id・customer_id・amount・created_at)のテーブルで再現しました。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「column reference is ambiguousの直し方|SQL」
再現:どちらにもある列(id・created_at)
-- PostgreSQL
ERROR: column reference "id" is ambiguous
LINE 1: SELECT id, name, amount FROM amb_c c JOIN amb_o o ON o.custo...
^
-- MySQL
ERROR 1052 (23000): Column 'id' in field list is ambiguous
PostgreSQL では ^ が、MySQL では in field list・in where clause などが、場所を示します。 id のように分かりやすい列だけでなく、created_at・updated_at・name・status など、多くのテーブルに付けている列でよく起きます。
-- WHERE で created_at(どちらのテーブルにもある)
PostgreSQL: ERROR: column reference "created_at" is ambiguous
MySQL: ERROR 1052 (23000): Column 'created_at' in where clause is ambiguous
テーブルにあとから列を足したら、今まで動いていた SQL がこのエラーになることがあります。注文テーブルに created_at を足したら、顧客の created_at で絞っていた SQL が止まった、という形です。JOIN する SQL では、すべての列に別名を付けておくと防げます。
ORDER BY・GROUP BY は、DB によって結果が違う
SELECT に c.id だけを書き、ORDER BY・GROUP BY には id とだけ書いたときの結果です。
| SQL | PostgreSQL 16 | MySQL 8.0 |
|---|---|---|
SELECT c.id, o.id ... ORDER BY id |
ORDER BY "id" is ambiguous |
Column 'id' in order clause is ambiguous |
SELECT c.id ... ORDER BY id |
動く(SELECT の id を使う) |
動く |
SELECT c.id, count(*) ... GROUP BY id |
column reference "id" is ambiguous |
動く |
ORDER BY は SELECT に書いた列名を優先するので、SELECT に id が1つだけなら動きました(PostgreSQL の公式ドキュメントでも、ORDER BY は出力の列名を使うとされています)。一方、GROUP BY は、PostgreSQL ではエラー、MySQL では動きました。 MySQL から PostgreSQL へ移すと、ここで止まります。ORDER BY・GROUP BY にも別名を付けるのが確実です。
UPDATE の JOIN でも出る
mysql> UPDATE amb_c c JOIN amb_o o ON o.customer_id = c.id SET name = 'x', created_at = '2026-10-11';
ERROR 1052 (23000): Column 'created_at' in field list is ambiguous
更新する列にも別名が要ります(SET c.created_at = ...)。どちらのテーブルを更新するつもりかを、別名で明示します。
USING と NATURAL JOIN
| 書き方 | 動き |
|---|---|
JOIN ... USING (id) |
id が1つの列にまとまり、SELECT id と書いてもエラーにならない |
NATURAL JOIN |
同じ名前の列すべてで結合する |
SELECT count(*) FROM amb_c NATURAL JOIN amb_o;
count
-------
0
NATURAL JOIN は、エラーにはなりませんが、id と created_at の両方で結合し、0 件になりました(PostgreSQL・MySQL とも)。顧客の id と注文の id は別のものです。曖昧さを避けるために NATURAL JOIN にするのは逆効果で、ON に結合の条件を書くのが安全です。
PL/pgSQL:関数の引数・戻り値の名前と、列名がぶつかる
CREATE FUNCTION get_c(p int) RETURNS TABLE (id int, name text) LANGUAGE plpgsql AS $$
BEGIN
RETURN QUERY SELECT id, name FROM amb_c WHERE id = p;
END $$;
SELECT * FROM get_c(1);
ERROR: column reference "id" is ambiguous
LINE 1: SELECT id, name FROM amb_c WHERE id = p
^
DETAIL: It could refer to either a PL/pgSQL variable or a table column.
テーブルは1つしか使っていないのに、エラーになりました。 RETURNS TABLE (id int, name text) の id は、関数の中では変数として扱われ、テーブルの列 id と区別できないためです。DETAIL の a PL/pgSQL variable or a table column が目印です。PL/pgSQL は、既定ではこの場合にエラーにします(公式ドキュメント)。
| 直し方 | 書き方 | 結果(確認環境) |
|---|---|---|
| テーブルに別名を付けて書く | SELECT c.id, c.name FROM amb_c c WHERE c.id = p |
動いた(おすすめ) |
#variable_conflict use_column |
関数の先頭に書くと、列を優先する | 動いた |
| 変数の名前を変える | 戻り値を out_id などに(列と重ならない名前) |
戻り値の列名も変わる |
CREATE FUNCTION get_c3(p int) RETURNS TABLE (id int, name text) LANGUAGE plpgsql AS $$
#variable_conflict use_column
BEGIN
RETURN QUERY SELECT id, name FROM amb_c WHERE id = p;
END $$;
ON CONFLICT (id) でも出る
CREATE FUNCTION up_c(p int, n text) RETURNS TABLE (id int) LANGUAGE plpgsql AS $$
BEGIN
RETURN QUERY INSERT INTO amb_c (id, name) VALUES (p, n)
ON CONFLICT (id) DO UPDATE SET name = n RETURNING amb_c.id;
END $$;
ERROR: column reference "id" is ambiguous
LINE 1: ...T INTO amb_c (id, name) VALUES (p, n) ON CONFLICT (id) DO UP...
^
ON CONFLICT (id) の id は別名を付けられないので、上の直し方1が使えません。 確認環境では、制約の名前で指定すると動きました。
INSERT INTO amb_c AS t (id, name) VALUES (p, n)
ON CONFLICT ON CONSTRAINT amb_c_pkey DO UPDATE SET name = n
RETURNING t.id;
#variable_conflict use_column を関数の先頭に書く方法でも避けられます。UPSERT の書き方全体は、関連記事の「SQL UPSERTの書き方|PostgreSQL・MySQL・MERGE構文比較表」で扱っています。
同じ内容を LANGUAGE sql の関数で書いたときは、エラーにならず動きました。 PL/pgSQL に書き換えたら出るようになった、という場合はこの違いです。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | どの列か | エラー文の "id"・'id' と、^・in ... clause |
| 2 | どのテーブルにその列があるか | JOIN しているテーブルを順に見る |
| 3 | 別名を付ける | SELECT・WHERE・ORDER BY・GROUP BY・UPDATE の SET |
| 4 | DETAIL に PL/pgSQL variable |
関数の引数・RETURNS TABLE の名前と、列名がぶつかっている |
| 5 | 関数の中 | テーブルに別名、#variable_conflict use_column、ON CONFLICT ON CONSTRAINT |
| 6 | NATURAL JOIN を使っていないか | 同じ名前の列すべてで結合し、0 件になることがある |
よくある質問
Q. SQLSTATE は何ですか。
A. PostgreSQL は 42702(ambiguous_column)、MySQL は 23000 です(エラー番号は 1052)。
Q. 同じ名前の列を、両方とも結果に出したいときは。
A. SELECT o.id AS order_id, c.id AS customer_id のように、列に別の名前を付けます。確認環境でも、order_id・customer_id の2列で取得できました。
まとめ
- JOIN したテーブルに同じ名前の列があり、テーブルを書かなかったエラー
- 列名の前に別名を付ける(
c.id)。created_atなど共通の列名で起きやすい - 列を足すと、今まで動いていた SQL が止まることがある。JOIN する SQL は全部の列に別名を
- GROUP BY id は PostgreSQL ではエラー、MySQL では動く
- PL/pgSQL では、
RETURNS TABLEの名前と列名がぶつかる。別名、#variable_conflict use_column、ON CONFLICT ON CONSTRAINT - NATURAL JOIN は、意図しない列でも結合する
参考・出典
確認日はいずれも 2026年10月11日です。
- PostgreSQL 16 Documentation「PL/pgSQL under the Hood」(Variable Substitution):https://www.postgresql.org/docs/16/plpgsql-implementation.html
- PostgreSQL 16 Documentation「Sorting Rows (ORDER BY)」:https://www.postgresql.org/docs/16/queries-order.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「column reference is ambiguousの直し方|SQL」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。