できない.dev

PostgreSQL で「column does not exist」が解消できない(列は存在するのに)

列があるのに column does not exist になる典型は、大文字を含む列名の引用符の問題。
引用符なしの識別子は小文字へ畳まれるため、大文字を含めて作成された列はダブルクオートで参照する必要がある。

公開:

要約

テーブルに列が存在するのに ERROR: column "createdat" does not exist になる場合、ほとんどは大文字小文字と引用符の問題である。

PostgreSQL では引用符なしの識別子は自動的に小文字へ畳まれる。
一方、ダブルクオート付きで作られた識別子は大文字小文字がそのまま保存される。createdAt という列を引用符なしで参照すると createdat を探しに行くため、一致せずにこのエラーになる。

よくある原因

  1. 小文字への畳み込み: SELECT createdAt FROM users と書くと、PostgreSQL は createdat という列を探す(字句構造の公式ドキュメント(新しいタブで開く))。
  2. ORM が引用符付きで作成: Prisma や TypeORM などは camelCase の列を "createdAt" のように引用符付きで作るため、手書き SQL 側で引用符が必要になる。
  3. リテラルの引用符違い: PostgreSQL でダブルクオートは識別子用で、WHERE name = "alice" は文字列比較ではなく alice という列の参照になる。
  4. search_path 違い: 同名テーブルが複数スキーマにあり、列の無い方を見ている。

解決策

1. エラーメッセージの列名を手がかりにする

SELECT createdAt FROM users;
-- ERROR:  column "createdat" does not exist

エラー中の列名が全部小文字になっていたら、畳み込みが起きたサインである。

2. 大文字を含む列はダブルクオートで参照する

SELECT "createdAt" FROM users;

引用符付きで作られた識別子は、参照時も毎回同じ引用符付きで書く必要がある。

3. 実際の列名を確認する

\d users

psql の \d はテーブル定義を実際の大文字小文字のまま表示するので、どちらの形で作られたかを確定できる。

4. 文字列はシングルクオートで書く

SELECT * FROM users WHERE name = 'alice';

なお SQL 標準では引用符なしの識別子は大文字へ畳まれる規定で、PostgreSQL の小文字畳み込みは標準と逆である。
移植性を考えるなら「常に引用符を付ける」か「常に付けない(小文字スネークケース)」のどちらかに統一するのが安全で、新規設計なら後者が扱いやすい。

この記事は役立ちましたか?