web-dev-qa-db-ja.com

PL / SQL:スクリプトの実行を完全に停止する指示はありますか?

PL/SQLスクリプトの冒頭でDBスキーマのいくつかのチェックを実行しようとしています。

チェックの結果が失敗した場合は、スクリプトを停止して、次の命令が実行されないようにします。

私はこのようなものを得ました

-- 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」の実行を許可する命令を探しています。

13
Frosty Z

質問は複数ステートメントのバッチスクリプトを示しています。 RAISE_APPLICATION_ERROR()は、PL/SQLブロック(サブプログラム)からのみ終了し、スクリプト全体(Justinが指摘)からではなく、後続のステートメントで続行します。

バッチスクリプトの場合は、WHENEVER SQLERROR EXITを使用するのが最適です。はい、それはSQLです標準SQLではなく、Plusディレクティブですが、かなり移植性があります。スクリプトをサポートする最も一般的なOracleツールは、少なくとも部分的にこのディレクティブをサポートします。次の例はSQLで機能します Plus、SQL *行をコメントアウトすると、開発者、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プラスはエラーで終了する可能性がありますが、残りのバッファされたコマンドはOSシェルによって処理されます。これは、シェルコマンドがコメント(これは前代未聞ではありません)。 SQLPlusでは、接続してからスクリプトを実行するか、<start>コマンドライン引数(sqlplus scott/tiger @ foo.sql)に渡してスクリプトを渡さないようにするのが常に最善です。

13
codenheim

例外を発生させたくない場合は、(テストされていない)のようなものを試すことができます:

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ステートメントを嫌う人もいますが、このような単純な状況では(ここでも、例外を発生させたくない場合)、問題なく動作します。

8
tbone

グーグルでさらに数秒答えが得られました:関数RAISE_APPLICATION_ERROR()

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

ユーザー定義のエラーコードは-20000から-20999の間でなければなりません。

Oracleドキュメントの詳細はこちら: http://docs.Oracle.com/cd/B10501_01/appdev.920/a96624/07_errs.htm#877 (sectionDefining独自のエラーメッセージ:プロシージャRAISE_APPLICATION_ERROR

5
Frosty Z

アプリケーションエラーをスローするのではなく、現在のPL/SQLブロックを非常にスムーズに終了する RETURN keyword を使用する方がはるかに簡単です。

もちろん、その前にDBMS_OUTPUT.PUT_LINE('Exited because <error')を実行して、ユーザーにコースを終了する理由を示す素敵なメッセージを提供してください。

2
Jonny