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 * плюс запускаете в окне консоли. 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()Определяемый пользователем код ошибки должен находиться в диапазоне от -20000 до -20999.IF (SOME_COUNT > 0) THEN RAISE_APPLICATION_ERROR(-20000, 'Test failed'); END IF;Подробности о 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