2009-11-19 19 views
81

En una secuencia de comandos de MySQL puede escribir:PostgreSQL crean tabla si no existe

CREATE TABLE IF NOT EXISTS foo ...; 

... otras cosas ...

y luego se puede ejecutar el script muchas veces sin volver a crear la mesa.

¿Cómo se hace esto en PostgreSQL?

+0

@ErwinBrandstetter: Esto podría estar reviviendo un hilo muy antiguo sin propósito, pero el enlace que proporcionó apunta a esta misma página. –

Respuesta

1

No existe CREAR TABLA SI NO EXISTE ... pero se puede escribir un procedimiento simple para que, algo así como:

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

Eso es un poco raro, pero puede ser simplemente

+0

dentro de un desencadenador no siempre funciona: https://gist.github.com/igilfanov/4df5e90d8a88d653132746a223639f45 ERROR: la relación "foo" ya existe – igilfanov

117

Este característica ha sido implemented in Postgres 9.1:

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



Para mayores versiones, aquí es una función para trabajar alrededor de ella:

CREATE OR REPLACE FUNCTION create_mytable() 
    RETURNS void AS 
$func$ 
BEGIN 
    IF EXISTS (SELECT 1 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; 

Llamar:

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

Si el usuario no tiene los privilegios necesarios para crear la tabla que podría quiere usar SECURITY DEFINER. Esta versión es lo suficientemente segura.

+0

Me veo obligado a utilizar una base de datos existente de postgres 8.4. Este hack hace el truco, ¡gracias! – Boundless

+0

@Boundless: vi que su edición se rechazó como "demasiado pequeña". Lo apliqué, porque no duele. Sin embargo, debe ejecutar 'CREATE FUNCTION' solo una vez. Es 'SELECT create_mytable();' que puede querer llamar muchas veces. –

+0

Brandstetter: estoy de acuerdo contigo. El problema con el que me encontré fue que no sabía si la función se había creado o no (al igual que la tabla puede existir o no). Así que quiero asegurarme de que la función se crea antes de llamarlo. – Boundless

5

creé una solución genérica de las respuestas existentes que pueden ser reutilizados para cualquier tabla:

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; 

Uso:

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

Se podría simplificarse aún más a tomar sólo un parámetro si uno extraería el nombre de la tabla del parámetro de consulta. También dejé fuera los esquemas. Siéntase libre de extender mi solución si sabe cómo hacerlo; todavía no estoy tan metido en plpgsql (esta es la primera vez que estoy lidiando con eso).

1

Esta solución es algo similar a la respuesta de Erwin Brandstetter, pero utiliza solo el lenguaje sql.

No todas las instalaciones de PostgreSQL tienen el lenguaje plpqsql por defecto, esto significa que debe llamar al CREATE LANGUAGE plpgsql antes de crear la función y luego eliminar el idioma nuevamente para dejar la base de datos en el mismo estado que estaba antes (pero solo si la base de datos no tenía el lenguaje plpgsql para empezar). ¿Ves cómo crece la complejidad?

Agregar plpgsql puede no ser un problema si está ejecutando el script localmente; sin embargo, si el script se usa para configurar un esquema en un cliente, puede no ser conveniente dejar cambios como este en la base de datos de clientes.

Esta solución está inspirada en a post by 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(); 
23

Prueba esto:

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

esta es realmente la solución más limpia. debería ser votado. – SDReyes

+2

de hecho, me aterroriza la cantidad de soluciones que implican 'función'. – SDReyes

+4

@SDReyes esas otras soluciones se publicaron antes de Postgres 9.1 que incluía la opción 'IF NOT EXISTS'. – Kris

1

No existe Crear una tabla SI NO EXISTE ... pero se puede escribir un procedimiento simple para que, algo así como:

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; 
Cuestiones relacionadas