PostgreSQL oluşturma tablosu yoksa


175

Bir MySQL betiğinde şunları yazabilirsiniz:

CREATE TABLE IF NOT EXISTS foo ...;

... diğer şey ...

ve sonra tabloyu yeniden oluşturmadan komut dosyasını birçok kez çalıştırabilirsiniz.

PostgreSQL'de bunu nasıl yaparsınız?

Yanıtlar:


279

Bu özellik Postgres 9.1'de uygulanmıştır :

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



Daha eski sürümler için , etrafta bir işlev vardır:

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;

Aramak:

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

Notlar:

  • Sütunlar schemanameve tablenameiçinde pg_tablesküçük harfe duyarlıdır. İfadede tanımlayıcıları iki kez tırnak içine CREATE TABLEalırsanız, aynı yazımı kullanmanız gerekir. Bunu yapmazsanız, küçük harfli dizeler kullanmanız gerekir. Görmek:

  • pg_tablesyalnızca gerçek tablolar içerir . Tanımlayıcı hala ilgili nesneler tarafından işgal edilmiş olabilir. Görmek:

  • Rol Eğer yürütme bu işlevi tablo oluşturmak için gerekli ayrıcalıklara sahip değil Kullanmak isteyebileceğiniz SECURITY DEFINERfonksiyon için ve bunu yapmak olunan gerekli ayrıcalıkları olan başka bir rolde tarafından. Bu sürüm yeterince güvenlidir.


Mevcut bir postgres 8.4 veritabanı kullanmak zorundayım. Bu kesmek hile yapar, teşekkür ederim!
Sınırsız

1
@ Sınırsız: Düzenlemenizin "çok küçük" olarak reddedildiğini gördüm. Ben uyguladım, çünkü acıtmayacak. Ancak, CREATE FUNCTIONyalnızca bir kez çalıştırmalısınız . Bu var SELECT create_mytable();sen defalarca aramak istediğini biliyoruz.
Erwin Brandstetter

1
Brandstetter: Sana katılıyorum. Karşılaştığım sorun, işlevin yaratılıp yaratılmadığını bilmiyordum (tıpkı tablonun var olup olmadığı gibi). Bu yüzden çağırmadan önce işlevin yaratıldığından emin olmak istiyorum.
Sınırsız

84

Bunu dene:

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)
)

bu aslında daha temiz bir çözüm. kaldırılmalıdır.
SDReyes

4
Aslında, 'işlev' içeren kaç çözümün varlığından korkuyorum.
SDReyes

8
Bu diğer çözümler IF NOT EXISTSseçeneği içeren Postgres 9.1'den önce yayınlanmıştır .
Kris

2
@ Erwin-brandstetter cevabı kendi içinde tamamlandığından bu cevabın nasıl katkıda bulunduğundan emin değilim.
Ocak'ta

@comiventor doğru, bu nasıl hiç parametre kullanımı olduğunu gösterir. Bu biraz yardımcı olur.
Kızgın 84

8

Herhangi bir tablo için yeniden kullanılabilen mevcut cevaplar dışında genel bir çözüm oluşturdum:

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;

Kullanımı:

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

Tablo adını sorgu parametresinden çıkarırsa yalnızca bir parametre almak daha da basitleştirilebilir. Ayrıca şemaları da bıraktım.


3

Bu çözüm Erwin Brandstetter'in cevabına biraz benziyor, ancak sadece sql dilini kullanıyor.

Tüm PostgreSQL kurulumları varsayılan olarak plpqsql diline sahip değildir, bu CREATE LANGUAGE plpgsql, işlevi oluşturmadan önce aramanız gerekebilir ve daha sonra, veritabanını daha önce olduğu gibi bırakmak için dili tekrar kaldırmanız gerektiği anlamına gelir (ancak yalnızca veritabanı başlamak için plpgsql dili yoktu). Karmaşıklığın nasıl büyüdüğünü görüyor musunuz?

Komut dosyanızı yerel olarak çalıştırıyorsanız plpgsql eklemek sorun yaratmayabilir, ancak komut dosyası bir müşteriye şema ayarlamak için kullanılıyorsa, bunun gibi değişiklikleri müşteri veritabanında bırakmak istenmeyebilir.

Bu çözüm, Andreas Scherbaum'un bir gönderisinden esinlenmiştir .

-- 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 kullanılabilir olduğunda bile çözümünüz harika. Zamanında mevcut olmayan nesneler üzerinde görünüm ve işlevlerin oluşturulması için genişletilebilir. Örneğin, yabancı sunuculardan alınan tabloların görünümleri. Günümü kurtardın! Teşekkürler!
Alex Yu

3

VARSA, OLUŞTUR TABLOSU yoktur ... ancak bunun için basit bir prosedür yazabilirsiniz, şöyle bir şey:

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

VARSA, OLUŞTUR TABLOSU yoktur ... ancak bunun için basit bir prosedür yazabilirsiniz, şöyle bir şey:

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'
  );

bir tetik içinde her zaman işe yaramaz: gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45 HATA: ilişki "foo" zaten var
igilfanov
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.