Restrições
Você pode perguntar ao catálogo do sistema
pg_database
- acessível de qualquer banco de dados no mesmo cluster de banco de dados. A parte complicada é que CREATE DATABASE
só pode ser executado como uma única instrução. O manual:
CREATE DATABASE
não pode ser executado dentro de um bloco de transação.
Portanto, não pode ser executado diretamente dentro de uma função ou
DO
declaração, onde estaria dentro de um bloco de transação implicitamente. Os procedimentos SQL, introduzidos com o Postgres 11, também não podem ajudar nisso. Solução de dentro do psql
Você pode contornar isso de dentro do psql executando a instrução DDL condicionalmente:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
O manual:
\gexec
Envia o buffer de consulta atual para o servidor e trata cada coluna de cada linha da saída da consulta (se houver) como uma instrução SQL a ser executada.
Solução do shell
Com
\gexec
você só precisa chamar psql uma vez :echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Você pode precisar de mais opções do psql para sua conexão; função, porta, senha, ... Veja:
- Executar arquivo em lote com comando psql sem senha
O mesmo não pode ser chamado com
psql -c "SELECT ...\gexec"
desde \gexec
é um meta‑comando do psql e o -c
opção espera um único comando para o qual o manual afirma:
command
deve ser uma string de comando que seja completamente analisável pelo servidor (ou seja, não contém recursos específicos do psql) ou um único comando de barra invertida. Assim, você não pode misturar meta-comandos SQL e psql dentro de um-c
opção.
Solução de dentro da transação do Postgres
Você pode usar um
dblink
conexão de volta ao banco de dados atual, que é executado fora do bloco de transação. Portanto, os efeitos também não podem ser revertidos. Instale o módulo adicional dblink para isso (uma vez por banco de dados):
- Como usar (instalar) o dblink no PostgreSQL?
Então:
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$;
Novamente, você pode precisar de mais opções do psql para a conexão. Veja a resposta adicionada de Ortwin:
- Simular CREATE DATABASE IF NOT EXISTS para PostgreSQL?
Explicação detalhada para dblink:
- Como faço grandes atualizações sem bloqueio no PostgreSQL?
Você pode tornar isso uma função para uso repetido.