Предотвратить ошибку при удалении несуществующих последовательностей, создании существующих пользователей

У меня есть куча сценариев sql, которые создают / удаляют последовательности, пользователей и другие объекты. Я запускаю эти сценарии через Liquibase, но они терпят неудачу, потому что oracle жалуется, когда я пытаюсь удалить несуществующую последовательность или создать существующего пользователя.

Есть ли способ оракула предотвратить ошибки?

Что-то в этом роде

Создайте пользователя / последовательность, если не существует

Отбросьте пользователя / безопасность, если существует

Насколько я знаю, у меня есть такие варианты:

  • Напишите скрипт plsql
  • Используйте контексты Liquibase.
  • Используйте предварительные условия Liquibase, но это будет означать слишком много работы.

Будем очень признательны за любые мысли / идеи.


person Tom    schedule 26.10.2009    source источник


Ответы (5)


Liquibase имеет атрибут failOnError, который вы можете установить в false в наборах изменений, которые включают вызов, который может завершиться ошибкой.

<changeSet failOnError="false">
   <createSequence sequenceName="new_sequence"/>
</changeSet>

Это позволяет вам просто создать пользователя, создать последовательность, удалить пользователя и удалить набор изменений последовательности, и если оператор выдает ошибку, потому что эти пользователи / последовательности существуют / не существуют, они все равно будут помечены как запущенные, и обновление будет продолжено.

Обратной стороной этого подхода является то, что он также будет отмечать их как запущенные и продолжать, если они ошибаются по какой-либо другой причине (неправильные разрешения, сбой подключения, недопустимый SQL и т. Д.). Более точный подход - использовать предварительные условия, например:

<changeSet>
   <preconditions onFail="MARK_RAN"><not><sequenceExists/></not></preconditions>
   <createSequence name="new_sequence"/>
</changeSet>

В настоящее время предварительного условия userExists нет, но вы можете создать собственные предварительные условия или вернуться к предварительному условию. См. Документацию http://www.liquibase.org/documentation/preconditions.html.

person Nathan Voxland    schedule 26.10.2009
comment
Я рассмотрел предварительные условия, но остается одно сомнение: если у меня есть N операторов создания последовательности, должен ли я создавать равное количество наборов изменений? - person Tom; 27.10.2009
comment
Да, ты должен. ChangeSets пытается быть транзакционным, но базы данных часто автоматически фиксируют вызовы DDL, такие как создание последовательности. Таблица databasechangelog, которую Liquibase использует для отслеживания запущенных наборов изменений, просто отслеживает все запущенные наборы изменений, поэтому, если у вас есть 15 вызовов create sequence в одном наборе изменений и по какой-то причине 8-й выдает ошибку, обновление Liquibase завершится ошибкой при первом запуске. из-за этой ошибки, и с этого момента changeSet всегда будет терпеть неудачу, потому что первая последовательность уже существует. Следовательно, лучший подход - иметь один вызов DDL для каждого набора изменений. - person Nathan Voxland; 30.10.2009
comment
синтаксис для Liquibase 3.4.2 изменился, атрибут name теперь sequenceName - person chrismarx; 18.07.2016

Напишите функцию do_ddl, подобную этой, и перехватите все исключения, которые вы хотите перехватить:

DECLARE
   allready_null EXCEPTION;
   PRAGMA EXCEPTION_INIT(allready_null, -1451);
BEGIN
   execute immediate 'ALTER TABLE TAB MODIFY(COL  NULL)';
EXCEPTION
   WHEN allready_null THEN
      null; -- handle the error
END;
/
person Rob van Laarhoven    schedule 26.10.2009

Я бы просто использовал анонимный блок PL / SQL.

begin
   for x in (select sequence_name
             from   user_sequences
              where sequence_name in ('SEQ1','SEQ2' ... 'SEQn'))
   loop
      execute immediate 'drop sequence '||x.sequence_name;
   end loop;
end;
/
person David Aldridge    schedule 26.10.2009

По моему опыту, основываясь на поведении Liquibase 3.5.1, при использовании failOnError = "false" changeSet не записывается как RAN, если операция завершилась неудачно. Мне это кажется ошибкой, и ответ Натана не кажется правильным?

Обратной стороной этого подхода является то, что он также будет отмечать их как запущенные и продолжать, если они ошибаются по какой-либо другой причине (неправильные разрешения, сбой соединения, недопустимый SQL и т. Д.). Более точный подход - использовать предварительные условия, например:

То есть: он не отмечает их как запущенные!

person consultantleon    schedule 23.07.2016

Предварительные условия Liquibase не проверяли существующие последовательности для меня. Итак, после нескольких попыток я попробовал простой <changeSet id="test-id"><sql> DROP SEQUENCE IF EXISTS "TABLENAME_ID_seq"; </sql></changeSet>

person Ramz_the_dev    schedule 26.12.2018