PostgreSQL ERROR: relation "table_name" does not exist の修正方法

beginner🐘 PostgreSQL2026-03-18| PostgreSQL 12+, Linux/macOS/Windows, psql CLI, pgAdmin, 任意のPostgreSQLクライアント

Error Message

ERROR: relation "table_name" does not exist
#postgresql#table#schema#relation

エラーの内容

ERROR: relation "table_name" does not exist
LINE 1: SELECT * FROM table_name;
                      ^

確かに動くはずのクエリを実行しているのに、PostgreSQL がテーブルは存在しないと言う。pgAdmin ではちゃんと見えているのに。このエラーはほぼ毎回4つの原因のどれかで、データが消えたわけではありません。

なぜこのエラーが起きるか

PostgreSQL がクエリを受け取ったが、テーブルの参照を解決できない状態です。テーブル自体は問題ない場合がほとんどです。原因は大抵、以下のいずれかです:

  • テーブルが別のスキーマにあり、search_path に含まれていない
  • 大文字小文字の区別"Users" のようにクォートを使った混合ケースで作成されている
  • 誤ったデータベースに接続している(複数環境では頻繁に起きる)
  • テーブルが本当に存在しない — マイグレーションが実行されていないか、誤った環境で実行された
  • 別セッションの一時テーブルである — 一時テーブルはセッションスコープで、他からは見えない

手順別の修正方法

手順1:テーブルが実際に存在するか確認する

まず最初に、テーブルが実際に存在するか確認します:

-- 全スキーマのテーブルを一覧表示
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_name = 'your_table_name';

または psql で:

\dt *.*

結果が出ない場合、テーブルは存在しません。マイグレーションファイルを確認するか、CREATE TABLE 文を手動で実行してください。

手順2:スキーマと search_path を確認する

PostgreSQL はデフォルトで public スキーマを参照します。多くの本番環境では appapireporting などのカスタムスキーマを使用しており、search_path にそれらが含まれていない場合、これらのテーブルへのクエリはすべてこのエラーで失敗します。

-- 現在の search_path を確認
SHOW search_path;

-- 現在のスキーマを確認
SELECT current_schema();

テーブルが app というスキーマにある場合、3つの方法があります:

-- オプション A: テーブル名にスキーマを明示する
SELECT * FROM app.users;

-- オプション B: このセッションの search_path にスキーマを追加する
SET search_path TO app, public;
SELECT * FROM users;

-- オプション C: 現在のユーザーに対して永続的に設定する
ALTER ROLE your_user SET search_path TO app, public;

手順3:大文字小文字の区別を確認する

これは誰もが一度は引っかかる落とし穴です。PostgreSQL はクォートなしの識別子をすべて小文字に変換します。そのため UsersusersUSERS はすべて同じものとして扱われます。例外はダブルクォートで作成されたテーブルです。

-- このように作成された場合:
CREATE TABLE "Users" (id serial, name text);

-- これは失敗する(PostgreSQL は小文字の "users" を探す):
SELECT * FROM users;

-- これは成功する:
SELECT * FROM "Users";

実際に保存されている名前を確認するには:

SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public';

結果に混合ケースの名前が含まれている場合、すべてのクエリでクォートが必要になります。長期的に楽な対処法は、テーブル作成時にアンダースコア区切りの小文字に統一すること — UserAccounts ではなく user_accounts を使いましょう。

手順4:正しいデータベースに接続しているか確認する

PostgreSQL の各データベースは完全に独立しています。db_production 内のテーブルは、同じサーバーでも db_staging への接続からは見えません。これは Docker や CI パイプラインで DATABASE_URL が意図せず別の場所を指している際によく起きる落とし穴です。

-- 現在のデータベースを確認
SELECT current_database();

-- psql でデータベースを切り替える(再接続が必要)
\c correct_database_name

アプリで接続文字列を使用している場合は、.env または設定ファイルのデータベース名を再確認してください。

手順5:ビューまたはシーケンスかどうか確認する

存在しないビューやシーケンスを参照した場合も同じエラーが発生します。すべてのオブジェクトタイプを一度に検索できます:

SELECT schemaname, tablename, 'テーブル' AS type FROM pg_tables WHERE tablename = 'target_name'
UNION ALL
SELECT schemaname, viewname, 'ビュー' FROM pg_views WHERE viewname = 'target_name'
UNION ALL
SELECT schemaname, sequencename, 'シーケンス' FROM pg_sequences WHERE sequencename = 'target_name';

修正の確認

変更後の簡単な確認:

-- 行または空のセットが返るはず — エラーではない
SELECT * FROM your_schema.your_table LIMIT 5;

-- 正しいスキーマとデータベースにいることを確認
SELECT current_schema(), current_database();

ロールの search_path を変更した場合は、一度切断して再接続し、設定が永続化されているか確認してください。

クイックヒント

  • テーブル名はアンダースコア区切りの小文字で統一"UserOrders" ではなく user_orders。大文字小文字の問題を根本的に解消できます。
  • スキーマプレフィックスを明示するschema.table)方が search_path より信頼性が高い。複数環境で動くアプリコードでは特に有効です。
  • マイグレーション実行前に SELECT current_database(), current_schema(); を実行して、正しい場所を対象にしているか確認しましょう。
  • Docker や CI 環境では、誤った設定の DATABASE_URL が間違ったデータベースを指していることが、ローカル開発以外でのこのエラーの最大の原因です。
  • Django と SQLAlchemy はどちらも明示的なスキーマ設定をサポートしています。psql では動くのにアプリで失敗する場合は Meta.db_table__table_args__ を確認してください。

Related Error Notes