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".

814   4  

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 * плюс запускаете в окне консоли. SQL * Plus может завершиться ошибкой, но оставшиеся буферизованные команды будут обработаны оболочкой операционной системы, что немного грязно и потенциально рискованно, если у вас были команды оболочки в комментариях (что не является неслыханным). С помощью SQLPlus всегда лучше подключиться, а затем выполнить сценарий или передать его в аргументе командной строки (sqlplus Скотт / тигр @foo.sql), чтобы избежать этого.

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

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, поскольку они могут привести к спагетти-коду при злоупотреблении, но в простых ситуациях, подобных этой (опять же, предполагая, что вы не хотите создавать исключение), они работают хорошо imo.

Еще несколько секунд гугления дали мне ответ: функция 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') перед ним, чтобы предоставить пользователю хорошее сообщение о том, почему вы выходите, конечно!

Comments

    Ничего не найдено.