web-dev-qa-db-ja.com

特定のスキーマにテーブルが存在するかどうかを確認する方法

Postgres 8.4以降のデータベースにはpublicスキーマに共通のテーブルがあり、companyスキーマに会社固有のテーブルがあります。
companyスキーマ名は常に'company'で始まり、会社番号で終わります。
したがって、次のようなスキーマがあるかもしれません。

public
company1
company2
company3
...
companynn

アプリケーションは常に単一の会社で機能します。
search_pathは、odbcまたはnpgsql接続文字列で次のように指定されています。

search_path='company3,public'

特定のテーブルが特定のcompanynスキーマに存在するかどうかをどのように確認しますか?

例えば:

select isSpecific('company3','tablenotincompany3schema')

falseを返すべきで、

select isSpecific('company3','tableincompany3schema')

trueが返されるはずです。

どのような場合でも、関数は渡されたcompanynスキーマのみをチェックし、他のスキーマはチェックしません。

特定のテーブルがpublicと渡されたスキーマの両方に存在する場合、関数はtrueを返す必要があります。
Postgres 8.4以降で動作するはずです。

120
Andrus

テストする対象によって異なりますexactly

情報スキーマ?

「テーブルが存在するかどうか」(誰が尋ねても)を見つけるには、情報スキーマ(information_schema.tables)のクエリはincorrect、厳密に言えば、( per documentation ):

現在のユーザーがアクセスできるテーブルとビューのみが表示されます(所有者である、または何らかの特権を持つ)。

クエリ @kongで示されるFALSEを返すことができますが、テーブルはまだ存在できます。それは質問に答えます:

テーブル(またはビュー)が存在し、現在のユーザーがそれにアクセスできるかどうかを確認する方法は?

SELECT EXISTS (
   SELECT 1
   FROM   information_schema.tables 
   WHERE  table_schema = 'schema_name'
   AND    table_name = 'table_name'
   );

情報スキーマは、主に、メジャーバージョン間および異なるRDBMS間で移植性を維持するのに役立ちます。しかし、Postgresは洗練されたビューを使用して標準に準拠する必要があるため、実装は遅くなります(information_schema.tablesはかなり単純な例です)。また、一部の情報(OIDなど)は、システムカタログからの翻訳で失われます-実際にはすべての情報を保持しています。

システムカタログ

あなたの質問は:

テーブルが存在するかどうかを確認する方法は?

SELECT EXISTS (
   SELECT 1 
   FROM   pg_catalog.pg_class c
   JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
   WHERE  n.nspname = 'schema_name'
   AND    c.relname = 'table_name'
   AND    c.relkind = 'r'    -- only tables
   );

システムカタログpg_classおよびpg_namespaceを直接使用します。これもかなり高速です。ただし、 pg_classのドキュメントごと

カタログpg_classは、テーブルと、列を持っているかテーブルに類似している他のほとんどすべてをカタログします。これには、indexes(ただしpg_indexも参照)、sequencesviewsマテリアライズドビューコンポジットタイプ、およびTOASTテーブル;

この特定の質問には、 システムビューpg_tables も使用できます。主要なPostgresバージョン間で少しシンプルで移植性が高い(この基本的なクエリにはほとんど関心がありません):

SELECT EXISTS (
   SELECT 1 
   FROM   pg_tables
   WHERE  schemaname = 'schema_name'
   AND    tablename = 'table_name'
   );

識別子は、上記のallオブジェクト間で一意である必要があります。質問したい場合:

特定のスキーマ内のテーブルまたは同様のオブジェクトの名前が使用されているかどうかを確認する方法

SELECT EXISTS (
   SELECT 1 
   FROM   pg_catalog.pg_class c
   JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
   WHERE  n.nspname = 'schema_name'
   AND    c.relname = 'table_name'
   );

代替: regclass へのキャスト

SELECT 'schema_name.table_name'::regclass

(オプションでスキーマ修飾された)テーブル(またはその名前を占める他のオブジェクト)が存在しない場合、これは例外を発生させます

テーブル名をスキーマ修飾しない場合、regclassへのキャストはデフォルトで search_path になり、OID最初に見つかったテーブルの場合-またはテーブルがリストされたスキーマにない場合は例外。システムスキーマpg_catalogおよびpg_temp(現在のセッションの一時オブジェクトのスキーマ)は、自動的にsearch_pathの一部であることに注意してください。

それを使用して、関数で発生する可能性のある例外をキャッチできます。例:

上記のようなクエリは、可能な例外を回避するため、わずかに高速です。

to_regclass(rel_name) Postgres 9.4以降

より簡単になりました:

SELECT to_regclass('schema_name.table_name');

キャストと同じ、 but返される...

...名前が見つからない場合はエラーをスローするのではなくnull

235

おそらく information_schema :を使ってください。

SELECT EXISTS(
    SELECT * 
    FROM information_schema.tables 
    WHERE 
      table_schema = 'company3' AND 
      table_name = 'tableincompany3schema'
);
41
kong

PostgreSQL 9.3以下の場合...またはテキストに正規化されたものがすべて好きな人

私の古いSwissKnifeライブラリには、relname_exists(anyThing)relname_normalized(anyThing)relnamechecked_to_array(anyThing)の3種類があります。すべて--- pg_catalog.pg_classテーブルからチェックし、標準のユニバーサルデータ型を返します(booleantextまたはtext [])。 。

/**
 * From my old SwissKnife Lib to your SwissKnife. License CC0.
 * Check and normalize to array the free-parameter relation-name.
 * Options: (name); (name,schema), ("schema.name"). Ignores schema2 in ("schema.name",schema2).
 */
CREATE FUNCTION relname_to_array(text,text default NULL) RETURNS text[] AS $f$
     SELECT array[n.nspname::text, c.relname::text]
     FROM   pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace,
            regexp_split_to_array($1,'\.') t(x) -- not work with quoted names
     WHERE  CASE
              WHEN COALESCE(x[2],'')>'' THEN n.nspname = x[1]      AND c.relname = x[2]
              WHEN $2 IS NULL THEN           n.nspname = 'public'  AND c.relname = $1
              ELSE                           n.nspname = $2        AND c.relname = $1
            END
$f$ language SQL IMMUTABLE;

CREATE FUNCTION relname_exists(text,text default NULL) RETURNS boolean AS $wrap$
  SELECT EXISTS (SELECT relname_to_array($1,$2))
$wrap$ language SQL IMMUTABLE;

CREATE FUNCTION relname_normalized(text,text default NULL,boolean DEFAULT true) RETURNS text AS $wrap$
  SELECT COALESCE(array_to_string(relname_to_array($1,$2), '.'), CASE WHEN $3 THEN '' ELSE NULL END)
$wrap$ language SQL IMMUTABLE;
0
Peter Krauss