PostgreSQLが存在しない場合はテーブルを作成


175

MySQLスクリプトでは、次のように記述できます。

CREATE TABLE IF NOT EXISTS foo ...;

... 他のもの ...

その後、テーブルを再作成せずにスクリプトを何度も実行できます。

PostgreSQLでこれをどのように行いますか?

回答:


279

この機能はPostgres 9.1で実装されています

CREATE TABLE IF NOT EXISTS myschema.mytable (i integer);



古いバージョン、ここでそれを回避するには関数は次のとおりです。

CREATE OR REPLACE FUNCTION create_mytable ()
  RETURNS void AS
$func$
BEGIN
   IF EXISTS (SELECT FROM pg_catalog.pg_tables 
              WHERE  schemaname = 'myschema'
              AND    tablename  = 'mytable') THEN
      RAISE NOTICE 'Table myschema.mytable already exists.';
   ELSE
      CREATE TABLE myschema.mytable (i integer);
   END IF;
END
$func$ LANGUAGE plpgsql;

コール:

SELECT create_mytable();        -- call as many times as you want. 

ノート:

  • schemanametablenamepg_tablesは大文字と小文字が区別されます。CREATE TABLEステートメントで識別子を二重引用符で囲む場合は、まったく同じスペルを使用する必要があります。そうでない場合は、小文字の文字列を使用する必要があります。見る:

  • pg_tables実際のテーブルのみが含まれます。識別子はまだ関連オブジェクトによって占有されている可能性があります。見る:

  • この関数を実行するロールに、テーブルを作成するために必要な特権がない場合SECURITY DEFINER、その関数に使用し、必要な特権を持つ別のロールによって所有されるようにすることができます。このバージョンは十分に安全です。


既存のpostgres 8.4データベースを使用せざるを得ません。このハックはトリックをします、ありがとう!
無限の

1
@無制限:あなたの編集が「あまりにもマイナー」として拒否されたのを見ました。痛くないので適用しました。ただし、CREATE FUNCTION一度だけ実行する必要があります。それSELECT create_mytable();はあなたが何度も電話をかけたいかもしれないということです。
Erwin Brandstetter、2012年

1
Brandstetter:私はあなたに同意します。私が遭遇した問題は、関数が作成されたかどうかがわからないことです(テーブルが存在するかどうかと同じように)。そのため、呼び出す前に関数が作成されていることを確認します。
無限

84

これを試して:

CREATE TABLE IF NOT EXISTS app_user (
  username varchar(45) NOT NULL,
  password varchar(450) NOT NULL,
  enabled integer NOT NULL DEFAULT '1',
  PRIMARY KEY (username)
)

これは実際にはよりクリーンなソリューションです。賛成する必要があります。
SDReyes 2016

4
実際、私は「機能」を含むソリューションがいくつあるのか怖いです。
SDReyes 2016

8
@SDReyesこれらの他のソリューションは、IF NOT EXISTSオプションを含むPostgres 9.1より前に投稿されました。
Kris

2
@ erwin-brandstetterの回答自体が完全であったため、この回答がどのように貢献したかはわかりません。
委員

@comiventor正解です。これは、パラメーターの使用法がどのように示されるかを示しています。主な答えは、これを見るまでは見つけられませんでした。これは少し役立ちます。
Angry 84

8

私は既存の回答から任意のテーブルで再利用できる一般的なソリューションを作成しました:

CREATE OR REPLACE FUNCTION create_if_not_exists (table_name text, create_stmt text)
RETURNS text AS
$_$
BEGIN

IF EXISTS (
    SELECT *
    FROM   pg_catalog.pg_tables 
    WHERE    tablename  = table_name
    ) THEN
   RETURN 'TABLE ' || '''' || table_name || '''' || ' ALREADY EXISTS';
ELSE
   EXECUTE create_stmt;
   RETURN 'CREATED';
END IF;

END;
$_$ LANGUAGE plpgsql;

使用法:

select create_if_not_exists('my_table', 'CREATE TABLE my_table (id integer NOT NULL);');

クエリパラメータからテーブル名を抽出する場合は、パラメータを1つだけ取るようにさらに簡略化できます。また、スキーマも省略しました。


3

このソリューションは、Erwin Brandstetterの回答に多少似ていますが、SQL言語のみを使用しています。

すべてのPostgreSQLインストールにデフォルトでplpqsql言語があるわけではありません。つまりCREATE LANGUAGE plpgsql、関数を作成する前に呼び出す必要があり、その後、言語を再度削除して、データベースを以前と同じ状態のままにする必要があります(ただし、データベースがそもそもplpgsql言語がありませんでした)。複雑さがどのように増大するかをご覧ください。

スクリプトをローカルで実行している場合、plpgsqlの追加は問題にならない可能性がありますが、スクリプトを使用して顧客でスキーマを設定する場合、このような変更を顧客データベースに残しておくことは望ましくない場合があります。

このソリューションは、Andreas Scherbaumによる投稿に触発されまし

-- Function which creates table
CREATE OR REPLACE FUNCTION create_table () RETURNS TEXT AS $$
    CREATE TABLE table_name (
       i int
    );
    SELECT 'extended_recycle_bin created'::TEXT;
    $$
LANGUAGE 'sql';

-- Test if table exists, and if not create it
SELECT CASE WHEN (SELECT true::BOOLEAN
    FROM   pg_catalog.pg_tables 
    WHERE  schemaname = 'public'
    AND    tablename  = 'table_name'
  ) THEN (SELECT 'success'::TEXT)
  ELSE (SELECT create_table())
END;

-- Drop function
DROP FUNCTION create_table();

plpgsqlが使用可能な場合でも、ソリューションは優れています。現時点では存在しないオブジェクトのビューや関数を作成するために簡単に拡張できます。たとえば、外部サーバーからのテーブルのビュー。あなたは私の日を救った!ありがとう!
Alex Yu

3

CREATE TABLE IF NOT EXISTS ...はありませんが、次のような簡単な手順を記述できます。

CREATE OR REPLACE FUNCTION prc_create_sch_foo_table() RETURNS VOID AS $$
BEGIN

EXECUTE 'CREATE TABLE /* IF NOT EXISTS add for PostgreSQL 9.1+ */ sch.foo (
                    id serial NOT NULL, 
                    demo_column varchar NOT NULL, 
                    demo_column2 varchar NOT NULL,
                    CONSTRAINT pk_sch_foo PRIMARY KEY (id));
                   CREATE INDEX /* IF NOT EXISTS add for PostgreSQL 9.5+ */ idx_sch_foo_demo_column ON sch.foo(demo_column);
                   CREATE INDEX /* IF NOT EXISTS add for PostgreSQL 9.5+ */ idx_sch_foo_demo_column2 ON sch.foo(demo_column2);'
               WHERE NOT EXISTS(SELECT * FROM information_schema.tables 
                        WHERE table_schema = 'sch' 
                            AND table_name = 'foo');

         EXCEPTION WHEN null_value_not_allowed THEN
           WHEN duplicate_table THEN
           WHEN others THEN RAISE EXCEPTION '% %', SQLSTATE, SQLERRM;

END; $$ LANGUAGE plpgsql;

3

CREATE TABLE IF NOT EXISTS ...はありませんが、次のような簡単な手順を記述できます。

CREATE OR REPLACE FUNCTION execute(TEXT) RETURNS VOID AS $$
BEGIN
  EXECUTE $1;
END; $$ LANGUAGE plpgsql;


SELECT 
  execute($$
      CREATE TABLE sch.foo 
      (
        i integer
      )
  $$) 
WHERE 
  NOT exists 
  (
    SELECT * 
    FROM information_schema.tables 
    WHERE table_name = 'foo'
      AND table_schema = 'sch'
  );

トリガー内で常に機能するとは限らない:gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45エラー:リレーション「foo」はすでに存在しています
igilfanov
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.