PostgreSQL не підтримує IF NOT EXISTSдля CREATE DATABASEзаяви. Він підтримується лише в CREATE SCHEMA. Більше того, CREATE DATABASEне може бути видано транзакцією, тому воно не може бути в DOблоці з вилученням виключень.
Коли CREATE SCHEMA IF NOT EXISTSвипущено і схема вже існує, то виникає повідомлення (не помилка) з подвійною інформацією про об'єкт.
Для вирішення цих проблем вам потрібно використовувати dblinkрозширення, яке відкриває нове підключення до сервера баз даних та виконувати запит без укладання транзакцій. Ви можете повторно використовувати параметри з'єднання, подаючи порожню рядок.
Нижче наведено PL/pgSQLкод, який повністю імітує CREATE DATABASE IF NOT EXISTSтаку саму поведінку, як у CREATE SCHEMA IF NOT EXISTS. Він викликає CREATE DATABASEчерез dblink, duplicate_databaseвиключення catch (який видається, коли база даних вже існує) і перетворює його в повідомлення з поширенням errcode. Повідомлення рядка додається , skippingтак само, як це робиться 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
$$;
Це рішення не має жодних умов перегонів, як в інших відповідях, де база даних може бути створена зовнішнім процесом (або іншим екземпляром того ж сценарію) між перевіркою наявності бази даних та її власним створенням.
Більше того, коли CREATE DATABASEпомилки з іншою помилкою, ніж база даних вже існує, ця помилка поширюється як помилка, а не мовчки відкидається. Є лише улов на duplicate_databaseпомилку. Тож воно справді поводиться як IF NOT EXISTSслід.
Ви можете ввести цей код у власну функцію, зателефонувати йому безпосередньо або з транзакції. Просто відкат (відновлення випалої бази даних) не буде працювати.
Тестовий вихід (викликається два рази через DO, а потім безпосередньо):
$ 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.