Как написать сценарий SQL для создания РОЛИ в PostgreSQL 9.1, но без появления ошибки, если она уже существует?
В текущем скрипте просто есть:
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
Это не удается, если пользователь уже существует. Я бы хотел что-то вроде:
IF NOT EXISTS (SELECT * FROM pg_user WHERE username = 'my_user')
BEGIN
CREATE ROLE my_user LOGIN PASSWORD 'my_password';
END;
... но это не работает - IF
похоже, не поддерживается в простом SQL.
У меня есть командный файл, который создает базу данных PostgreSQL 9.1, роль и некоторые другие вещи. Он вызывает psql.exe, передавая имя запускаемого сценария SQL. Пока что все эти сценарии представляют собой простой SQL, и я бы по возможности избегал PL / pgSQL и т.п.
$
в вашем клиенте есть особое значение, вам нужно избежать его в соответствии с правилами синтаксиса вашего клиента. Попробуйте убежать$
с\$
в Linux оболочку. Или начните новый вопрос - комментариям не место. Вы всегда можете ссылаться на этот для контекста.Принятый ответ страдает от состояния гонки, если два таких сценария выполняются одновременно в одном кластере Postgres (сервере БД), как это часто бывает в средах непрерывной интеграции .
Как правило, безопаснее попытаться создать роль и аккуратно решить проблемы при ее создании:
источник
DUPLICATE_OBJECT
это точное условие в этом случае, если вы не хотите ловить практически все условия с помощьюOTHERS
.Или, если роль не является владельцем каких-либо объектов db, которые можно использовать:
Но только если падение этого пользователя не причинит никакого вреда.
источник
Альтернатива Bash (для сценариев Bash ):
(это не ответ на вопрос! Это только для тех, кто может быть полезен)
источник
FROM pg_roles WHERE rolname
вместоFROM pg_user WHERE usename
Вот общее решение с использованием plpgsql:
Использование:
источник
В некоторых ответах предлагалось использовать шаблон: проверьте, не существует ли роли, а если нет, выполните
CREATE ROLE
команду. У этого есть один недостаток: состояние гонки. Если кто-то другой создает новую роль между проверкой и выдачейCREATE ROLE
команды, то,CREATE ROLE
очевидно, происходит сбой с фатальной ошибкой.Чтобы решить вышеупомянутую проблему, в других ответах уже упоминалось использование
PL/pgSQL
,CREATE ROLE
безоговорочная выдача, а затем перехват исключений из этого вызова. У этих решений есть только одна проблема. Они молча отбрасывают любые ошибки, в том числе те, которые не связаны с тем, что роль уже существует.CREATE ROLE
может выдавать также другие ошибки, и симуляцияIF NOT EXISTS
должна заглушать только ошибку, когда роль уже существует.CREATE ROLE
выдаетduplicate_object
ошибку, когда роль уже существует. И обработчик исключений должен улавливать только эту одну ошибку. Как упоминалось в других ответах, рекомендуется преобразовать фатальную ошибку в простое уведомление. ДругиеIF NOT EXISTS
команды PostgreSQL добавляют, skipping
в свои сообщения, поэтому для единообразия я добавляю их и здесь.Вот полный код SQL для моделирования
CREATE ROLE IF NOT EXISTS
с правильным исключением и распространением sqlstate:Тестовый вывод (вызывается дважды через DO, а затем напрямую):
источник
Поскольку вы используете версию 9.x, вы можете обернуть это в оператор DO:
источник
Моя команда столкнулась с ситуацией с несколькими базами данных на одном сервере, в зависимости от того, к какой базе данных вы подключились, рассматриваемая РОЛЬ не была возвращена
SELECT * FROM pg_catalog.pg_user
, как было предложено @ erwin-brandstetter и @a_horse_with_no_name. Условный блок выполнен, и мы попалиrole "my_user" already exists
.К сожалению, мы не уверены в точных условиях, но это решение позволяет обойти проблему:
Возможно, его можно было бы сделать более конкретным, чтобы исключить другие исключения.
источник
Вы можете сделать это в своем командном файле, проанализировав вывод:
а затем запускается
psql.exe
еще раз, если роль не существует.источник
То же решение, что и для Simulate CREATE DATABASE IF NOT EXISTS для PostgreSQL? должно работать - отправьте
CREATE USER …
на\gexec
.Обходной путь из psql
Обходной путь из оболочки
См. Принятый ответ для более подробной информации.
источник