【豆知識】「リレーションは存在しません」のエラーを解決したい
PostgreSQLインサイド
実現方法
FROM句にスキーマ名で修飾せずにテーブル名を指定して、SELECT文などのSQLを実行したときに、「リレーションは存在しません」(英語環境では「relation does not exist」)のエラーメッセージが出力されることがあります。これは、目的のテーブルが存在するスキーマが、スキーマ検索パス(search_path:検索対象となるスキーマのリスト)に設定されていないことが原因である可能性があります。
このような場合、スキーマ検索パスの設定を確認し、対象となるスキーマが存在しない場合は追加してください。
実行例
前提
PostgreSQLでは、データベース作成時に「public」というスキーマがデフォルトで作成されます。自分のユーザー名と同じ名前のスキーマなど、別のスキーマを追加するには、CREATE SCHEMAコマンドで追加できます。
下の図のように、データベース「test_db」にユーザー「user01」が所有するスキーマ「user01」が存在し、テーブル「product」が作成済みとなっているものとします。そして、テーブル「product」へのアクセス権を持つユーザー「user02」がスキーマ修飾(「スキーマ名.テーブル名」の形式)せずにFROM句にテーブル「product」を指定してSELECTコマンドを実行します。なお、「user01」および「user02」は共に「product」へのアクセス権を持つものとします。
PostgreSQLはスキーマ検索パスに設定されたスキーマ名を検索してテーブルを特定します。このとき、対象のテーブルが見つからないと、以下例のようなエラーが出力されます。
ERROR: リレーション"product"は存在しません
対処例
スキーマ検索パスの設定を確認し、対象となるスキーマが存在しない場合は追加します。ユーザー「user02」でtest_dbに接続して、以下のように操作します。
-
スキーマ検索パスの設定内容を確認
SHOWコマンドの使用例と出力例を下記に示します。
test_db=> SHOW search_path;
search_path
-----------------
"$user", public
(1 行)
"$user"とpublicが検索対象のスキーマであることが判ります。また、検索はスキーマ検索パスの先頭から順に実行されるので、このケース(デフォルト)では、"$user"、publicの順で検索されます。
"$user"は現行ユーザーと同じ名前のスキーマ(この例ではuser02)を意味しますので、目的とするテーブル「product」が存在するスキーマ「user01」は、スキーマ検索パスに無いことがわかります。
なお、SELECT文などで、存在しないスキーマがスキーマ検索パスに指定されていた場合、そのスキーマは無視され、次に指定されているスキーマが検索されます。
-
SETコマンドでスキーマ検索パスに「user01」を追加
ここでは、一般ユーザーでも現在のセッション中だけ設定を変更できる、SETコマンドの使用例を以下に示します。
test_db=> SET search_path TO "$user", user01, public;
この例では、現行ユーザーと同名のスキーマ(user02)、user01、publicの順で検索するよう指定しています。
なお、もしスキーマ「user01」とスキーマ「public」に同じ名前のテーブルが存在した場合は、最初に検出されるテーブル、つまりスキーマ「user01」に属するテーブルが参照されます。
ポイント
-
エラーを解決するには、スキーマ検索パスの設定を変更する方法のほかに、テーブル名をスキーマ名で修飾して指定する方法もあります(例:user01.product)。アプリケーション開発の設計段階で、どちらの方法にするかの方針を決めておくことをお勧めします。
-
スキーマ検索パスを設定するには、SETコマンド以外にも以下の方法があります。
-
設定ファイルpostgresql.confファイルのsearch_pathパラメーターに設定
データベースクラスタにアクセス可能なすべてのユーザーに対して、デフォルトのスキーマ検索パスとして永続的に設定されます。初期値では「"$user", public」が設定されています。変更する場合は、検索させたい順番でスキーマ名を記載します。
以下にスキーマ検索パスにスキーマ「user01」を追加する例を示します。search_path = "$user", user01, public
変更後は、pg_ctlコマンドをreloadオプションで実行して設定ファイルを再読み込みし、変更を反映してください。
-
ALTER ROLEコマンドで特定のユーザーに対して設定
特定のユーザーにおいて、デフォルトのスキーマ検索パスとして永続的に設定されます。
以下にユーザー「user02」のスキーマ検索パスにスキーマ「user01」を追加する例を示します。ALTER ROLE user02 SET search_path TO "$user", user01, public;
-
-
スキーマが適用される仕組みは、SELECTコマンドによるテーブル参照時だけでなく、CREATE TABLEコマンドでテーブル作成先のスキーマを省略した場合にも適用されます。例えば、search_pathパラメーターのデフォルトの設定で以下のような操作をすると、public.t1のテーブルが作成されます。
CREATE TABLE t1(id int);
-
備考PostgreSQL 15以降では、新しいデータベースが作成された時、データベース所有者とスーパーユーザーだけがデフォルトのpublicスキーマでオブジェクトを作成することができるよう変更されました。
¥dtコマンドでテーブル一覧を表示すると、以下例のように作成されていることが確認できます。
test_db=> ¥dt リレーション一覧 スキーマ | 名前 | タイプ | 所有者 ----------+------+----------+-------- public | t1 | テーブル | user03
-
-
各データベースには、publicスキーマ、ユーザー作成のスキーマの他に、システムカタログスキーマ(pg_catalog)が含まれています。pg_catalogスキーマには、システムテーブルとすべての組み込みデータ型、関数、および演算子が含まれています。デフォルトではpg_catalogはスキーマ検索パスの先頭に暗黙的に含まれており、優先して検索されます。もし、pg_catalogスキーマの検索順を先頭以外に変更したい場合は、明示的にスキーマ検索パスにpg_catalogを追加します。
-
スキーマ検索パスに設定したスキーマに、目的とするテーブルが存在するかは、以下例のようなスキーマ内のテーブル名一覧を出力(例:スキーマ名「user01」)する¥dtコマンドを実行します。
¥dt user01.*
コマンドが実行されると以下例のように表示され、存在が確認できます。
リレーション一覧 スキーマ | 名前 | タイプ | 所有者 ----------+-------+----------+-------- user01 | sales | テーブル | user01
参考
PostgreSQL 14文書
-
Documentation(PostgreSQLオフィシャル)
- II. The SQL Language
- 5.9 Schemas
- 5.9.3 The Schema Search Path
- 5.9 Schemas
- II. The SQL Language
-
PostgreSQL日本語ドキュメント(日本PostgreSQLユーザ会)
- II. SQL言語
- 5.9. スキーマ
- 5.9.3 スキーマ検索パス
- 5.9. スキーマ
- II. SQL言語
2023年4月12日更新
富士通のソフトウェア公式チャンネル(YouTube)
-
- 富士通のミドルウェア製品のご紹介や各種イベント・セミナーの講演内容、デモンストレーションなどの動画をご覧いただけます。
- 富士通のミドルウェア製品のご紹介や各種イベント・セミナーの講演内容、デモンストレーションなどの動画をご覧いただけます。
PostgreSQLについてより深く知る
PostgreSQLに興味をお持ちのお客様はこちらのコンテンツもお勧めです。ぜひご覧ください。
本コンテンツに関するお問い合わせ
お電話でのお問い合わせ
-
富士通コンタクトライン(総合窓口)
0120-933-200受付時間:9時~12時および13時~17時30分(土曜日・日曜日・祝日・当社指定の休業日を除く)