PostgreSQL no es compatible IF NOT EXISTSpara la CREATE DATABASEdeclaración. Solo se admite en CREATE SCHEMA. Además CREATE DATABASE, no se puede emitir en transacción, por lo que no puedeDO bloque con excepción de captura.
Cuando CREATE SCHEMA IF NOT EXISTS se emite y el esquema ya existe, se genera un aviso (no un error) con información de objeto duplicada.
Para resolver estos problemas, debe usar la dblinkextensión que abre una nueva conexión al servidor de la base de datos y ejecutar la consulta sin ingresar a la transacción. Puede reutilizar los parámetros de conexión proporcionando una cadena vacía.
A continuación se muestra el PL/pgSQLcódigo que simula completamente CREATE DATABASE IF NOT EXISTScon el mismo comportamiento que enCREATE SCHEMA IF NOT EXISTS . Llama a CREATE DATABASEtravés de la excepción de dblinkcaptura duplicate_database(que se emite cuando la base de datos ya existe) y la convierte en un aviso con propagación errcode. El mensaje de cadena se ha agregado , skippingde la misma manera que lo hace CREATE SCHEMA IF NOT EXISTS.
CREATE EXTENSION IF NOT EXISTS dblink;
DO $$
BEGIN
PERFORM dblink_exec('', 'CREATE DATABASE testdb');
EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
Esta solución no tiene ninguna condición de carrera como en otras respuestas, donde la base de datos puede ser creada por un proceso externo (u otra instancia del mismo script) entre verificar si la base de datos existe y su propia creación.
Además, cuando CREATE DATABASEfalla con otro error que la base de datos ya existe, este error se propaga como error y no se descarta silenciosamente. Solo hay una trampa para el duplicate_databaseerror. Entonces realmente se comporta como IF NOT EXISTSdebería.
Puede poner este código en su propia función, llamarlo directamente o desde la transacción. Solo la reversión (restaurar la base de datos eliminada) no funcionaría.
Prueba de salida (llamada dos veces a través de DO y luego directamente):
$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.
postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
NOTICE: 42710: extension "dblink" already exists, skipping
LOCATION: CreateExtension, extension.c:1539
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE: 42P04: database "testdb" already exists, skipping
LOCATION: exec_stmt_raise, pl_exec.c:3165
DO
postgres=#
postgres=# CREATE DATABASE testdb;
ERROR: 42P04: database "testdb" already exists
LOCATION: createdb, dbcommands.c:467
dblink_connect.