PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Simuler CREATE DATABASE IF NOT EXISTS pour PostgreSQL ?

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.