PostgreSQL unterstützt nicht IF NOT EXISTSfür CREATE DATABASEAnweisung. Es wird nur in unterstützt CREATE SCHEMA. Darüber hinaus CREATE DATABASEkann es nicht in einer Transaktion ausgegeben werden, daher kann es DOmit Ausnahme des Fangens nicht blockiert werden.
Wenn CREATE SCHEMA IF NOT EXISTSausgegeben wird und das Schema bereits vorhanden ist, wird ein Hinweis (kein Fehler) mit doppelten Objektinformationen ausgelöst.
Um diese Probleme zu lösen, müssen Sie die dblinkErweiterung verwenden, die eine neue Verbindung zum Datenbankserver herstellt und die Abfrage ausführt, ohne eine Transaktion abzuschließen. Sie können Verbindungsparameter wiederverwenden, indem Sie eine leere Zeichenfolge angeben.
Unten finden Sie PL/pgSQLCode, der CREATE DATABASE IF NOT EXISTSmit demselben Verhalten wie in vollständig simuliert CREATE SCHEMA IF NOT EXISTS. Es ruft CREATE DATABASEvia dblink, catch- duplicate_databaseAusnahme auf (die ausgegeben wird, wenn die Datenbank bereits vorhanden ist) und konvertiert sie mit Propagierung in Benachrichtigung errcode. Die String-Nachricht wurde , skippingauf die gleiche Weise angehängt wie sie CREATE SCHEMA IF NOT EXISTS.
CREATE EXTENSION IF NOT EXISTS dblink;
DO $$
BEGIN
PERFORM dblink_exec('', 'CREATE DATABASE testdb');
EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;
Diese Lösung ist ohne Race-Bedingung wie in anderen Antworten, bei denen die Datenbank durch einen externen Prozess (oder eine andere Instanz desselben Skripts) zwischen der Überprüfung, ob eine Datenbank vorhanden ist, und ihrer eigenen Erstellung erstellt werden kann.
Wenn ein CREATE DATABASEFehler mit einem anderen Fehler als der Datenbank bereits vorliegt, wird dieser Fehler als Fehler weitergegeben und nicht stillschweigend verworfen. Es gibt nur duplicate_databaseFehler. Es verhält sich also wirklich so, wie es IF NOT EXISTSsollte.
Sie können diesen Code in eine eigene Funktion einfügen, direkt oder über eine Transaktion aufrufen. Nur ein Rollback (wiederhergestellte Datenbank wiederherstellen) würde nicht funktionieren.
Testausgabe (zweimal über DO und dann direkt aufgerufen):
$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.
postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=#
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
NOTICE: 42710: extension "dblink" already exists, skipping
LOCATION: CreateExtension, extension.c:1539
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE: 42P04: database "testdb" already exists, skipping
LOCATION: exec_stmt_raise, pl_exec.c:3165
DO
postgres=#
postgres=# CREATE DATABASE testdb;
ERROR: 42P04: database "testdb" already exists
LOCATION: createdb, dbcommands.c:467
dblink_connect.