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.