9

Oracle パッケージで使用する必要がある一連の更新ステートメントがあります。まれですが、更新ステートメントの 1 つが「単一行のサブクエリが 1 つ以上の行を返します」エラーをスローする結果となる、時折の避けられないユーザー エラーが発生する場合があります。

私はOracle PL/SQlの例外処理を調べていましたが、パッケージがクラッシュしないように、この例外をキャッチする方法と何を使用するかについて少し行き詰まっています。

事前に作成された「Too Many Rows」例外句が存在することは知っていますが、私が読んだものはすべて、それが不適切な挿入ステートメントに使用されていると言っているようです。

これを例外として使用できますか? または、独自の例外句を作成する必要がありますか。私はこれまで自分で構築したことがなく、必要なものすべてをどこに置くかについて大まかな考えしかありません。

次のコードは基本的に、この特定の手順で更新を設定する方法ですが、簡潔にするために、外観の基本的な例のみを使用しています。

INSERT INTO TempTable... --(Initial insert statement)

UPDATE TempTable t SET t.Row_one = (SELECT (Statement_One))
WHERE T.Row_One is NULL

UPDATE TempTable t SET t.Row_one = (SELECT (Statement_Two))
WHERE T.Row_One is NULL

UPDATE TempTable t SET t.Row_one = (SELECT (Statement_Three))
WHERE T.Row_One is NULL

-- Does the exception clause start here?
EXCEPTION
    WHEN TOO_MANY_ROWS THEN
(What do I tell the Procedure to do here, what am I able to tell it to do?)

--end of updates that need the exception handling

-- more insert statements into other tables based on data from the preceding Temp Table

END;

これは機能しますか、それともカスタム例外を作成する必要がありますか?

前もって感謝します。

4

1 に答える 1

12

まず、TOO_MANY_ROWS 例外は、select ステートメントが複数の行を返すケースをキャッチしません。TOO_MANY_ROWS 例外は、複数の行を返す SELECT .. INTO ステートメントを発行したときの ORA-01422 に対するものです。あなたのケースで発生する例外は、ORA-01427、単一行のサブクエリが複数の行を返します。

プロシージャでこの特定のエラーを処理する場合は、EXCEPTION_INIT プラグマを使用して例外名をエラーに関連付けます。

too_many_values EXCEPTION;
PRAGMA EXCEPTION_INIT(too_many_values, -1427);

次に、例外ハンドラでこの名前を参照できます。

EXCEPTION
    WHEN TOO_MANY_VALUES THEN
       {perform your handler here}

ハンドラーに何を入れるかは、プロシージャーが何をするかによって異なります。呼び出し元に何らかのエラー コード/メッセージを返したい場合がよくあります。

PROCEDURE my_proc(p_one VARCHAR2, p_err OUT VARCHAR2) IS
    too_many_values EXCEPTION;
    PRAGMA EXCEPTION_INIT(too_many_values, -1427);
BEGIN
...
EXCEPTION
   WHEN TOO_MANY_VALUES THEN
      p_err := 'More than one value available to assign in the update';
      RAISE;  -- re-raise the exception for the caller

   WHEN OTHERS THEN
      p_err := SQLERRM;  -- return the oracle message for the unexpected error
      RAISE;
END;

もう 1 つの方法は、特定の例外ハンドラをスキップして、WHEN OTHERS ハンドラで一般的なオラクル メッセージを返すことです。

EXCEPTION
  WHEN OTHERS THEN
    p_err := SQLERRM;
END;

最初のアプローチの利点は、プロセスからの出力がユーザーに直接フィードバックされる場合に、メッセージをエンドユーザーにとってより使いやすいようにカスタマイズできることです。後者のアプローチの利点は、必要なコーディングが少ないことです。エラー処理は重要であり、多くの場合、どのアプリケーションにおいても見過ごされがちです。

Oracle のドキュメントはこちらです。

編集:

これがパッケージであり、一連のプロシージャ呼び出しでエラー変数の長いチェーンを渡すのを避けたい場合は、パッケージ スコープでエラー変数を宣言し、エラーが発生したときにそれを設定し、エラーを再度 RAISE することができます。

PACKAGE BODY my_pkg is
  g_err  VARCHAR2(256);

PROCEDURE procx(... , p_err OUT VARCHAR2) IS...
  ...
  proc_y(p1);
EXCEPTION
  WHEN OTHERS THEN
    p_err := NVL(g_err, SQLERRM);
END;

PROCEDURE proc_y(p1 VARCHAR2) IS
...
proc_z(p2);

END;

PROCEDURE proc_z(p2 VARCHAR2) IS
  too_many_values EXCEPTION;
  PRAGMA EXCEPTION_INIT(too_many_values, -1427);
BEGIN
  ....
EXCEPTION
   WHEN TOO_MANY_VALUES THEN
      g_err := 'More than one value available to assign in the update';
      RAISE;  -- re-raise the exception for the caller
END;

proc_z で例外が発生すると、例外が処理されてから再度発生します。これは proc_y (そこにはハンドラーがない) を介して伝播し、proc_x でユーザーに返されます。グローバル g_err に設定されていないエラーは、一般的な Oracle エラー メッセージを取得します。これにより、パッケージ全体で初期エラー パラメータを渡す必要がなくなります。

于 2012-08-12T23:55:31.300 に答える