it-swarm.com.de

PostgreSQL-Tabelle erstellen, falls nicht vorhanden

In einem MySQL-Skript können Sie schreiben:

CREATE TABLE IF NOT EXISTS foo ...;

... andere Sachen ...

anschließend können Sie das Skript mehrmals ausführen, ohne die Tabelle neu zu erstellen.

Wie macht man das in PostgreSQL?

132
peter2108

Diese Funktion wurde implementiert in Postgres 9.1 :

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



Für ältere Versionen ist hier eine Funktion, um dies zu umgehen:

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;

Anruf:

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

Anmerkungen:

  • Bei den Spalten schemaname und tablename in pg_tables Wird zwischen Groß- und Kleinschreibung unterschieden. Wenn Sie Bezeichner in Anführungszeichen in der Anweisung CREATE TABLE Setzen, müssen Sie genau die gleiche Schreibweise verwenden. Wenn Sie dies nicht tun, müssen Sie Zeichenfolgen in Kleinbuchstaben verwenden. Sehen:

  • pg_tables Enthält nur aktuelle Tabellen. Die Kennung kann weiterhin von verwandten Objekten belegt sein. Sehen:

  • Wenn die Rolle wird ausgeführt diese Funktion nicht über die erforderlichen Berechtigungen verfügt, um die Tabelle zu erstellen, die Sie möglicherweise verwenden möchten SECURITY DEFINER für die Funktion und machen es = besessen von einer anderen Rolle mit den erforderlichen Berechtigungen. Diese Version ist sicher genug.

210

Versuche dies :

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

Aus den vorhandenen Antworten habe ich eine generische Lösung erstellt, die für jede Tabelle wiederverwendet werden kann:

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;

Verwendung:

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

Es könnte weiter vereinfacht werden, nur einen Parameter zu nehmen, wenn man den Tabellennamen aus dem Abfrageparameter extrahieren würde. Auch die Schemata habe ich weggelassen. Fühlen Sie sich frei, meine Lösung zu erweitern, wenn Sie wissen, wie man das macht - ich bin noch nicht so tief in plpgsql (dies ist das erste Mal, dass ich mich damit befasse).

6
Ingo Fischer

Es gibt keine CREATE TABLE WENN NICHT EXISTIERT ... aber Sie können eine einfache Prozedur dafür schreiben, so etwas wie:

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;
2
igilfanov

Es gibt keine CREATE TABLE WENN NICHT EXISTIERT ... aber Sie können eine einfache Prozedur dafür schreiben, so etwas wie:

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

Diese Lösung ähnelt der Antwort von Erwin Brandstetter, verwendet jedoch nur die SQL-Sprache.

Nicht alle PostgreSQL-Installationen haben standardmäßig die Sprache plpqsql. Dies bedeutet, dass Sie möglicherweise CREATE LANGUAGE plpgsql Aufrufen müssen, bevor Sie die Funktion erstellen, und anschließend die Sprache wieder entfernen müssen, um die Datenbank in demselben Zustand wie zuvor zu belassen (aber nur, wenn die Datenbank nicht die Sprache plpgsql hatte, mit der begonnen wurde). Sehen Sie, wie die Komplexität wächst?

Das Hinzufügen von plpgsql ist möglicherweise kein Problem, wenn Sie Ihr Skript lokal ausführen. Wenn das Skript jedoch zum Einrichten des Schemas bei einem Kunden verwendet wird, ist es möglicherweise nicht wünschenswert, solche Änderungen in der Kundendatenbank zu belassen.

Diese Lösung ist inspiriert von ein Beitrag von 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();
1
zpon