PL / SQL: есть ли инструкция полностью остановить выполнение скрипта?

Я пытаюсь выполнить некоторые проверки схемы БД в начале скрипта PL/SQL.

Если проверки дают неудачные результаты, я хочу остановить скрипт, чтобы предотвратить выполнение следующих инструкций.

у меня что-то вроде этого

-- 1st line of PL/SQL script

DECLARE
  SOME_COUNT INTEGER;
BEGIN
  SELECT COUNT(*) INTO SOME_COUNT FROM SOME_TABLE WHERE <SOME_CONDITIONS>;
  IF (SOME_COUNT > 0) THEN
    DBMS_OUTPUT.PUT_LINE('Test failed, I don''want the rest of the script'
      || ' to be executed.');
    --EXIT or something like that?... <= STOP EXECUTION HERE
  END IF;
END;
/

-- OTHER SQL INSTRUCTIONS...
ALTER TABLE SOME_TABLE ...

Я ищу инструкцию(ы), позволяющую делать "STOP EXECUTION HERE".

4 ответов


основываясь на вопросе, я не согласен с принятым ответом. В вопросе показан пакетный сценарий с несколькими операторами. RAISE_APPLICATION_ERROR () выходит только из блока PL/SQL (подпрограмма), а не из общего скрипта (как указал Джастин), поэтому он будет продолжаться с инструкциями, которые следуют.

для пакетных сценариев лучше всего использовать при выходе SQLERROR. Да, это директива SQL * Plus, а не стандартный SQL, но довольно портативный; большинство популярных инструментов Oracle, которые поддерживают скрипты поддерживают эту директиву, по крайней мере, частично. Следующий пример работает в SQL*Plus, SQL*Developer, Toad, SQLsmith и, возможно, других и демонстрирует проблему, если вы прокомментируете строку.

set serveroutput on

-- Without this line, things keep going
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK;

BEGIN
  IF (1 > 0) THEN
    DBMS_OUTPUT.PUT_LINE('First thing');
    RAISE_APPLICATION_ERROR(-20000, 'Test failed'); -- not enough
  END IF;
END;
/

-- This will execute if you remove WHEN SQLERROR.., so RAISE_APPLICATION_ERROR is not enough
BEGIN
   DBMS_OUTPUT.PUT_LINE('Second thing - Executes anyway');
END;
/

Если вы удалите WHEN SQLERROR, скрипт продолжит и выполнит 2-й блок и т. д. именно этого вопроса и следует избегать.

преимущество в этом случае графических инструментов, эмулирующих sqlplus, заключается в том, что они действительно останавливают скрипт и не отправляйте оставшуюся часть скрипта в командную оболочку как команды оболочки, что происходит, если вы вставляете скрипты в SQL*Plus, запущенные в окне консоли. SQL * Plus может выйти при ошибке, но остальные буферизованные команды будут обрабатываться оболочкой ОС, что немного грязно и потенциально рискованно, если у вас были команды оболочки в комментариях (что не является неслыханным). С SQLPlus всегда лучше подключиться, а затем выполнить сценарий или передать его в командной строке


Если вы не хотите создавать исключение, вы можете попробовать что-то вроде (непроверенное):

declare
  SOME_COUNT INTEGER;
begin
  SELECT COUNT(*) INTO SOME_COUNT FROM SOME_TABLE WHERE <SOME_CONDITIONS>;
  IF (SOME_COUNT > 0) THEN
    DBMS_OUTPUT.PUT_LINE('Test failed, I don''want the rest of the script'
      || ' to be executed.');

    goto end_proc;
  END IF;

  -- A bunch of great code here

  <<end_proc>>
  null;  -- this could be a commit or other lines of code
end;

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


еще несколько секунд googling дали мне ответ: функция RAISE_APPLICATION_ERROR()

  IF (SOME_COUNT > 0) THEN
    RAISE_APPLICATION_ERROR(-20000, 'Test failed');
  END IF;

пользовательский код ошибки должен находиться между -20000 и -20999.

подробности о Oracle doc здесь:http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/07_errs.htm#877 (раздел определение собственных сообщений об ошибках: процедура RAISE_APPLICATION_ERROR)


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

просто убедитесь, что вы делаете DBMS_OUTPUT.PUT_LINE('Exited because <error') перед ним, чтобы предоставить пользователю хорошее сообщение о том, почему вы выходите, конечно!