sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Simule CREAR BASE DE DATOS SI NO EXISTE para PostgreSQL?

Restricciones

Puede solicitar el catálogo del sistema pg_database - accesible desde cualquier base de datos en el mismo clúster de base de datos. La parte complicada es que CREATE DATABASE solo se puede ejecutar como una sola declaración. El manual:

CREATE DATABASE no se puede ejecutar dentro de un bloque de transacciones.

Por lo tanto, no se puede ejecutar directamente dentro de una función o DO declaración, donde estaría implícitamente dentro de un bloque de transacción. Los procedimientos SQL, introducidos con Postgres 11, tampoco pueden ayudar con esto.

Solución alternativa desde dentro de psql

Puede solucionarlo desde dentro de psql ejecutando la instrucción DDL de forma condicional:

SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec

El manual:

\gexec

Envía el búfer de consulta actual al servidor, luego trata cada columna de cada fila de la salida de la consulta (si corresponde) como una instrucción SQL para ser ejecutada.

Solución alternativa desde el shell

Con \gexec solo necesita llamar a psql una vez :

echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql

Es posible que necesite más opciones psql para su conexión; rol, puerto, contraseña, ... Ver:

  • Ejecutar archivo por lotes con el comando psql sin contraseña

Lo mismo no se puede llamar con psql -c "SELECT ...\gexec" desde \gexec es un metacomando de psql y el -c la opción espera un solo comando para lo cual el manual dice:

command debe ser una cadena de comando que el servidor pueda analizar completamente (es decir, no contiene características específicas de psql) o un solo comando de barra invertida. Por lo tanto, no puede mezclar metacomandos de SQL y psql dentro de un -c opción.

Solución alternativa desde dentro de la transacción de Postgres

Podrías usar un dblink conexión a la base de datos actual, que se ejecuta fuera del bloque de transacciones. Por lo tanto, los efectos tampoco se pueden revertir.

Instale el módulo adicional dblink para esto (una vez por base de datos):

  • ¿Cómo usar (instalar) dblink en PostgreSQL?

Entonces:

DO
$do$
BEGIN
   IF EXISTS (SELECT FROM pg_database WHERE datname = 'mydb') THEN
      RAISE NOTICE 'Database already exists';  -- optional
   ELSE
      PERFORM dblink_exec('dbname=' || current_database()  -- current db
                        , 'CREATE DATABASE mydb');
   END IF;
END
$do$;

Nuevamente, es posible que necesite más opciones de psql para la conexión. Vea la respuesta agregada de Ortwin:

  • ¿Simular CREAR BASE DE DATOS SI NO EXISTE para PostgreSQL?

Explicación detallada para dblink:

  • ¿Cómo realizo grandes actualizaciones sin bloqueo en PostgreSQL?

Puede hacer de esta una función para uso repetido.