ограничения
Вы можете запросить системный каталог pg_database
- доступный из любой базы данных в том же кластере баз данных. Сложность заключается в том, что CREATE DATABASE
можно выполнить только один оператор. Руководство:
CREATE DATABASE
не может быть выполнен внутри блока транзакции.
Таким образом, его нельзя запускать непосредственно внутри функции или DO
оператора, где он неявно будет внутри блока транзакции.
(Процедуры SQL, представленные в Postgres 11, тоже не могут помочь с этим .)
Обходной путь из psql
Вы можете обойти это из psql, условно выполнив оператор DDL:
SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec
Руководство:
\gexec
Отправляет текущий буфер запроса на сервер, а затем обрабатывает каждый столбец каждой строки вывода запроса (если есть) как инструкцию SQL, которая должна быть выполнена.
Обходной путь из оболочки
С \gexec
вам нужно только PSQL вызова один раз :
echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql
Вам может потребоваться больше параметров psql для вашего подключения; роль, порт, пароль, ... См .:
То же самое нельзя вызвать с помощью, psql -c "SELECT ...\gexec"
поскольку \gexec
это мета-команда psql, а -c
опция ожидает единственную команду, для которой указано в руководстве:
command
должна быть либо командной строкой, которая полностью анализируется сервером (т. е. не содержит специфичных для psql функций), либо одной командой с обратной косой чертой. Таким образом, вы не можете смешивать мета-команды SQL и psql в одном -c
параметре.
Обходной путь из транзакции Postgres
Вы можете использовать dblink
соединение с текущей базой данных, которая работает вне блока транзакции. Следовательно, эффекты также нельзя откатить.
Установите для этого дополнительный модуль dblink (один раз для каждой базы данных):
Затем:
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$;
Опять же, вам могут потребоваться дополнительные параметры psql для подключения. См. Добавленный ответ Ортвина:
Подробное объяснение для dblink:
Вы можете сделать эту функцию для многократного использования.
dblink_connect
.\gexec
когда я запустил первый запрос из оболочки, но это сработало.другая альтернатива, на всякий случай, если вы хотите иметь сценарий оболочки, который создает базу данных, если она не существует, а в противном случае просто сохраняет ее как есть:
Я обнаружил, что это полезно в сценариях подготовки DevOps, которые вы можете запускать несколько раз на одном и том же экземпляре.
источник
c:\Program Files\PostgreSQL\9.6\bin $ psql.exe -U admin -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U admin -c "CREATE DATABASE my_db" 'grep' is not recognized as an internal or external command, operable program or batch file.
Что я сделал не так ?grep
на вашем пути. В Windowsgrep
по умолчанию не устанавливается. Вы можетеgnu grep windows
выполнить поиск, чтобы найти версию, которая может работать в Windows.Мне пришлось использовать слегка расширенную версию, которую использовал @Erwin Brandstetter:
Мне пришлось включить
dblink
расширение, плюс я должен был предоставить учетные данные для dblink. Работает с Postgres 9.4.источник
Если вас не интересуют данные, вы можете сначала удалить базу данных, а затем воссоздать ее:
источник
PostgreSQL не поддерживает оператор
IF NOT EXISTS
forCREATE 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
viadblink
, catchduplicate_database
(которое выдается, когда база данных уже существует) и преобразует его в уведомление с распространениемerrcode
. Строковое сообщение добавлено так, skipping
же, как иCREATE SCHEMA IF NOT EXISTS
.Это решение не имеет какого-либо состояния гонки, как и в других ответах, где база данных может быть создана внешним процессом (или другим экземпляром того же сценария) между проверкой наличия базы данных и ее собственным созданием.
Более того, когда происходит
CREATE DATABASE
сбой с ошибкой, отличной от того, что база данных уже существует, эта ошибка распространяется как ошибка, а не игнорируется. Есть только ловушка дляduplicate_database
ошибки. Так что действительно ведет себя какIF NOT EXISTS
надо.Вы можете поместить этот код в собственную функцию, вызвать ее напрямую или из транзакции. Просто откат (восстановление удаленной базы данных) не сработает.
Тестирование вывода (вызывается дважды через DO, а затем напрямую):
источник
Если вы можете использовать оболочку, попробуйте
Я думаю, что
psql -U postgres -c "select 1" -d $DB
это прощеSELECT 1 FROM pg_database WHERE datname = 'my_db'
, и нужен только один тип цитаты, с которым легче комбинироватьsh -c
.Я использую это в своей недоступной задаче
источник
Просто создайте базу данных с помощью
createdb
инструмента CLI:Если база данных существует, она вернет ошибку:
источник
Обновитесь до PostgreSQL 9.5 или выше. Если (не) существует, было введено в версии 9.5.
источник
if not exists
дляCREATE DATABASE
- даже не в Postgres 11 postgresql.org/docs/current/static/sql-createdatabase.html