PL / SQL: есть ли инструкция, чтобы полностью остановить выполнение скрипта? - PullRequest
12 голосов
/ 18 января 2012

Я пытаюсь выполнить некоторые проверки схемы БД в начале сценария 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 ]

11 голосов
/ 16 мая 2014

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

Для пакетных сценариев лучше всего использовать WHENEVER SQLERROR EXIT. Да, это директива 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;
/

Если вы удалите WHER SQLERROR, сценарий продолжит работу и выполнит 2-й блок и т. Д., И это именно то, чего просит вопрос.

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

8 голосов
/ 18 января 2012

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

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.

5 голосов
/ 18 января 2012

Еще несколько секунд поиска в Google дали мне ответ: функция 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 )

2 голосов
/ 06 апреля 2016

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...