PostgreSQL membuat tabel jika tidak ada

175

Dalam skrip MySQL Anda dapat menulis:

CREATE TABLE IF NOT EXISTS foo ...;

... hal-hal lain ...

dan kemudian Anda bisa menjalankan skrip berkali-kali tanpa membuat ulang tabel.

Bagaimana Anda melakukannya di PostgreSQL?

peter2108
sumber

Jawaban:

279

Fitur ini telah diterapkan di Postgres 9.1 :

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



Untuk versi yang lebih lama , ini adalah fungsi untuk mengatasinya:

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;

Panggilan:

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

Catatan:

  • Kolom schemanamedan tablenamein pg_tablesadalah case-sensitive. Jika Anda mengutip ganda pengidentifikasi dalam CREATE TABLEpernyataan, Anda harus menggunakan ejaan yang sama persis. Jika tidak, Anda harus menggunakan string huruf kecil. Lihat:

  • pg_tableshanya berisi tabel aktual . Pengidentifikasi mungkin masih ditempati oleh objek terkait. Lihat:

  • Jika peran yang menjalankan fungsi ini tidak memiliki hak istimewa yang diperlukan untuk membuat tabel, Anda mungkin ingin menggunakan SECURITY DEFINERuntuk fungsi dan membuatnya dimiliki oleh peran lain dengan hak istimewa yang diperlukan. Versi ini cukup aman.

Erwin Brandstetter
sumber
Saya dipaksa untuk menggunakan database postgres 8.4 yang ada. Peretasan ini berhasil, terima kasih!
Tanpa batas
1
@ Tanpa Batas: Saya melihat bahwa hasil edit Anda ditolak sebagai "terlalu kecil". Saya menerapkannya, karena tidak ada salahnya. Namun, Anda harus menjalankan CREATE FUNCTIONhanya sekali. Mungkin SELECT create_mytable();Anda ingin menelepon berkali-kali.
Erwin Brandstetter
1
Brandstetter: Saya setuju dengan Anda. Masalah yang saya temui adalah bahwa saya tidak tahu apakah fungsi itu dibuat atau tidak (seperti tabel mungkin atau mungkin tidak ada). Jadi saya ingin memastikan fungsi dibuat sebelum saya menyebutnya.
Tanpa batas
84

Coba ini:

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)
)
Achilles Ram Nakirekanti
sumber
ini sebenarnya adalah solusi bersih. harus ditingkatkan.
SDReyes
4
sebenarnya, saya takut berapa banyak solusi yang melibatkan 'fungsi'.
SDReyes
8
@ SYDReyes solusi-solusi lain diposting sebelum Postgres 9.1 yang termasuk IF NOT EXISTSopsi.
Kris
2
Tidak yakin bagaimana jawaban ini berkontribusi karena jawaban @ erwin-brandstetter lengkap.
comiventor
@ comiventor benar, yang satu ini tidak pernah menunjukkan bahwa penggunaan parameter adalah. Jawaban utama saya tidak menemukan itu sampai saya melihat yang satu ini. Ini sedikit membantu.
Marah 84
8

Saya membuat solusi umum dari jawaban yang ada yang dapat digunakan kembali untuk tabel apa pun:

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;

Pemakaian:

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

Itu bisa disederhanakan lebih lanjut untuk mengambil hanya satu parameter jika seseorang akan mengekstrak nama tabel dari parameter kueri. Saya juga meninggalkan skema.

Ingo Fischer
sumber
3

Solusi ini agak mirip dengan jawaban oleh Erwin Brandstetter, tetapi hanya menggunakan bahasa sql.

Tidak semua instalasi PostgreSQL memiliki bahasa plpqsql secara default, ini berarti Anda mungkin harus memanggil CREATE LANGUAGE plpgsqlsebelum membuat fungsi, dan setelah itu harus menghapus bahasa lagi, untuk meninggalkan database dalam keadaan yang sama seperti sebelumnya (tetapi hanya jika database tidak memiliki bahasa plpgsql untuk memulai). Lihat bagaimana kompleksitas tumbuh?

Menambahkan plpgsql mungkin tidak menjadi masalah jika Anda menjalankan skrip Anda secara lokal, namun, jika skrip digunakan untuk mengatur skema di pelanggan, mungkin tidak diinginkan untuk meninggalkan perubahan seperti ini di database pelanggan.

Solusi ini terinspirasi oleh posting oleh 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();
zpon
sumber
Solusi Anda sangat bagus bahkan ketika plpgsql tersedia. Mudah diperluas untuk membuat tampilan dan fungsi pada objek yang tidak ada pada titik waktu. Misalnya tampilan pada tabel dari server asing. Kamu menyelamatkan hariku! Terima kasih!
Alex Yu
3

Tidak ada CREATE TABLE JIKA TIDAK ADA ... tetapi Anda dapat menulis prosedur sederhana untuk itu, sesuatu seperti:

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;
igilfanov
sumber
3

Tidak ada CREATE TABLE JIKA TIDAK ADA ... tetapi Anda dapat menulis prosedur sederhana untuk itu, sesuatu seperti:

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'
  );
Szymon Lipiński
sumber
di dalam pemicu tidak selalu berfungsi: gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45 GALAT: hubungan "foo" sudah ada
igilfanov