Restrictions
Vous pouvez demander au catalogue système pg_database
- accessible à partir de n'importe quelle base de données dans le même cluster de bases de données. La partie délicate est que CREATE DATABASE
ne peut être exécuté qu'en une seule instruction. Le manuel :
CREATE DATABASE
ne peut pas être exécuté à l'intérieur d'un bloc de transaction.
Il ne peut donc pas être exécuté directement dans une fonction ou DO
instruction, où il serait implicitement à l'intérieur d'un bloc de transaction. Les procédures SQL, introduites avec Postgres 11, ne peuvent pas aider non plus.
Solution depuis psql
Vous pouvez contourner ce problème depuis psql en exécutant conditionnellement l'instruction DDL :
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
Le manuel :
\gexec
Envoie le tampon de requête actuel au serveur, puis traite chaque colonne de chaque ligne de la sortie de la requête (le cas échéant) comme une instruction SQL à exécuter.
Solution depuis le shell
Avec \gexec
il suffit d'appeler psql une fois :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Vous aurez peut-être besoin de plus d'options psql pour votre connexion; rôle, port, mot de passe, ... Voir :
- Exécuter le fichier batch avec la commande psql sans mot de passe
La même chose ne peut pas être appelée avec psql -c "SELECT ...\gexec"
depuis \gexec
est une méta-commande psql et le -c
l'option attend une seule commande dont le manuel indique :
command
doit être soit une chaîne de commande entièrement analysable par le serveur (c'est-à-dire qu'elle ne contient aucune fonctionnalité spécifique à psql), soit une seule commande antislash. Ainsi, vous ne pouvez pas mélanger les méta-commandes SQL et psql dans un-c
option.
Solution de contournement depuis la transaction Postgres
Vous pouvez utiliser un dblink
connexion à la base de données actuelle, qui s'exécute en dehors du bloc de transaction. Les effets ne peuvent donc pas non plus être annulés.
Installez le module supplémentaire dblink pour cela (une fois par base de données) :
- Comment utiliser (installer) dblink dans PostgreSQL ?
Ensuite :
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$;
Encore une fois, vous aurez peut-être besoin de plus d'options psql pour la connexion. Voir la réponse ajoutée d'Ortwin :
- Simuler CREATE DATABASE IF NOT EXISTS pour PostgreSQL ?
Explication détaillée pour dblink :
- Comment effectuer des mises à jour volumineuses non bloquantes dans PostgreSQL ?
Vous pouvez en faire une fonction pour une utilisation répétée.