Restrizioni
Puoi chiedere al catalogo di sistema pg_database
- accessibile da qualsiasi database nello stesso cluster di database. La parte difficile è che CREATE DATABASE
può essere eseguito solo come una singola istruzione. Il manuale:
CREATE DATABASE
non può essere eseguito all'interno di un blocco di transazione.
Quindi non può essere eseguito direttamente all'interno di una funzione o DO
istruzione, dove sarebbe implicitamente all'interno di un blocco di transazione. Anche le procedure SQL, introdotte con Postgres 11, non possono essere d'aiuto.
Soluzione alternativa da psql
Puoi aggirarlo dall'interno di psql eseguendo l'istruzione DDL in modo condizionale:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
Il manuale:
\gexec
Invia il buffer della query corrente al server, quindi tratta ogni colonna di ogni riga dell'output della query (se presente) come un'istruzione SQL da eseguire.
Soluzione alternativa dalla shell
Con \gexec
devi solo chiamare psql una volta :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Potresti aver bisogno di più opzioni psql per la tua connessione; ruolo, porta, password, ... Vedi:
- Esegui file batch con il comando psql senza password
Lo stesso non può essere chiamato con psql -c "SELECT ...\gexec"
da \gexec
è un metacomando psql e il -c
l'opzione prevede un singolo comando per cui il manuale riporta:
command
deve essere una stringa di comando completamente analizzabile dal server (ovvero, non contiene funzionalità specifiche di psql) o un singolo comando barra rovesciata. Quindi non puoi combinare meta-comandi SQL e psql all'interno di un -c
opzione.
Soluzione alternativa dalla transazione Postgres
Potresti usare un dblink
connessione al database corrente, che viene eseguito al di fuori del blocco della transazione. Pertanto, anche gli effetti non possono essere annullati.
Installa il modulo aggiuntivo dblink per questo (una volta per database):
- Come usare (installare) dblink in PostgreSQL?
Quindi:
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$;
Ancora una volta, potresti aver bisogno di più opzioni psql per la connessione. Vedi la risposta aggiunta di Ortwin:
- Simula CREATE DATABASE SE NON ESISTE per PostgreSQL?
Spiegazione dettagliata per dblink:
- Come faccio a eseguire aggiornamenti non bloccanti di grandi dimensioni in PostgreSQL?
Puoi renderla una funzione per un uso ripetuto.