PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Simular CREATE DATABASE IF NOT EXISTS para PostgreSQL?

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.