【豆知識】「リレーションは存在しません」のエラーを解決したい
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に接続して、以下のように操作します。

  1. スキーマ検索パスの設定内容を確認

    SHOWコマンドの使用例と出力例を下記に示します。

test_db=> SHOW search_path;
   search_path
-----------------
 "$user", public
(1 行)

"$user"とpublicが検索対象のスキーマであることが判ります。また、検索はスキーマ検索パスの先頭から順に実行されるので、このケース(デフォルト)では、"$user"、publicの順で検索されます。
"$user"は現行ユーザーと同じ名前のスキーマ(この例ではuser02)を意味しますので、目的とするテーブル「product」が存在するスキーマ「user01」は、スキーマ検索パスに無いことがわかります。
なお、SELECT文などで、存在しないスキーマがスキーマ検索パスに指定されていた場合、そのスキーマは無視され、次に指定されているスキーマが検索されます。

  1. 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文書

2023年4月12日更新

オンデマンド(動画)セミナー

    • PostgreSQLに関連するセミナー動画を公開中。いつでもセミナーをご覧いただけます。
      • 【事例解説】運送業務改革をもたらす次世代の運送業界向けDXプラットフォームの構築
      • ハイブリッドクラウドに最適なOSSベースのデータベースご紹介

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ