PostgreSQL で「column does not exist」が解消できない(列は存在するのに)
列があるのに column does not exist になる典型は、大文字を含む列名の引用符の問題。
引用符なしの識別子は小文字へ畳まれるため、大文字を含めて作成された列はダブルクオートで参照する必要がある。
公開:
要約
テーブルに列が存在するのに ERROR: column "createdat" does not exist になる場合、ほとんどは大文字小文字と引用符の問題である。
PostgreSQL では引用符なしの識別子は自動的に小文字へ畳まれる。
一方、ダブルクオート付きで作られた識別子は大文字小文字がそのまま保存される。createdAt という列を引用符なしで参照すると createdat を探しに行くため、一致せずにこのエラーになる。
よくある原因
- 小文字への畳み込み:
SELECT createdAt FROM usersと書くと、PostgreSQL はcreatedatという列を探す(字句構造の公式ドキュメント(新しいタブで開く))。 - ORM が引用符付きで作成: Prisma や TypeORM などは camelCase の列を
"createdAt"のように引用符付きで作るため、手書き SQL 側で引用符が必要になる。 - リテラルの引用符違い: PostgreSQL でダブルクオートは識別子用で、
WHERE name = "alice"は文字列比較ではなくaliceという列の参照になる。 - search_path 違い: 同名テーブルが複数スキーマにあり、列の無い方を見ている。
解決策
1. エラーメッセージの列名を手がかりにする
SELECT createdAt FROM users;
-- ERROR: column "createdat" does not existエラー中の列名が全部小文字になっていたら、畳み込みが起きたサインである。
2. 大文字を含む列はダブルクオートで参照する
SELECT "createdAt" FROM users;引用符付きで作られた識別子は、参照時も毎回同じ引用符付きで書く必要がある。
3. 実際の列名を確認する
\d userspsql の \d はテーブル定義を実際の大文字小文字のまま表示するので、どちらの形で作られたかを確定できる。
4. 文字列はシングルクオートで書く
SELECT * FROM users WHERE name = 'alice';なお SQL 標準では引用符なしの識別子は大文字へ畳まれる規定で、PostgreSQL の小文字畳み込みは標準と逆である。
移植性を考えるなら「常に引用符を付ける」か「常に付けない(小文字スネークケース)」のどちらかに統一するのが安全で、新規設計なら後者が扱いやすい。