1

ユーザーが現在10件の注文のみを許可するトリガーを作成しました。したがって、顧客が注文番号11を出そうとすると、Oracleデータベースはエラーを返します。さて3つのエラー。

ORA-20000:現在、10件以上の注文を処理しています。

ORA-06512:「C3283535.TRG_ORDER_LIMIT」の12行目

ORA-04088:トリガー'C3283535.TRG_ORDER_LIMIT'の実行中にエラーが発生しました

一番上のエラーは、私が使用して作成したエラーです。

raise_application_error(-20000、'現在​​10件以上の注文を処理しています。');

検索して、他の2つのエラーのエラーメッセージを変更する方法や、ユーザーにすべてを一緒に表示しない方法を試してみたところ、疑問に思いました。

これが私が使用したコードです

    create or replace trigger trg_order_limit
    before insert on placed_order for each row  
    declare
    v_count number;
    begin
   -- Get current order count
   select count(order_id)
   into   v_count
   from   placed_order
   where  fk1_customer_id = :new.fk1_customer_id;

   -- Raise exception if there are too many
   if v_count >= 10 then
   EXCEPTION
   WHEN OTHERS THEN
    raise_application_error(-20000, 'You currently have 10 or more orders  processing.');
   end if;
   end;

どうもありがとうリチャード

4

3 に答える 3

4

外部ブロックから内部ブロックへの変数スコープとは対照的に、例外の伝播は内部ブロックから外部ブロックへと進みます。詳細については、McLaughlin の「PL/SQL によるプログラミング」の第 5 章を参照してください。

ここで取得しているのは例外スタックです。これは、最も内側のブロックから最も外側のブロックに発生した例外です。

トリガーから例外を発生させると、raise_application_errorステートメントはエラーを返します。

次に、トリガーブロックに伝播されますORA-06512: at "C3283535.TRG_ORDER_LIMIT", line 12。これは、トリガーが発生した例外をエラーとして扱い、続行を停止するためです。

次に、エラーが発生するセッションに伝播されORA-04088: error during execution of trigger 'C3283535.TRG_ORDER_LIMIT'ます。このエラーは、プログラムのどの部分でエラーが発生したかを報告します。

Java Server Pages や PHP などのフロントエンド プログラムを使用している場合は、発生したエラー (最初に 20000) をキャッチします。したがって、同じものをエンドユーザーに表示できます。

編集 :

最初のエラー - については、ステートメント自体ORA-20000で変更できます。RAISE_APPLICATION_ERROR

を処理したい場合はORA-06512、このエラーを処理して適切なエラー メッセージを表示するのに役立つ Uday Shankar の回答を使用できます。

ただし、最後のORA-04088. 私があなたの場所にいORA-20000た場合、ユーザーから他のすべての詳細を隠しながら、フロントエンド自体でアプリケーションエラーを発生させた後、心配する必要はありませんでした.

実際、これOracle の例外スタックの性質です。最も内側のブロックから最も外側のブロックまでのすべてのエラーが発生します。これは、エラーの正確な原因を特定するのに役立ちます。

于 2013-03-21T13:00:44.653 に答える
2

トリガーでは、以下に示すように例外処理部分を追加できます。

EXCEPTION
    WHEN OTHERS THEN
        raise_application_error(-20000, 'You currently have 10 or more orders processing.');
于 2013-03-21T13:03:36.693 に答える
0

これはかなり古い投稿だと思いますが、読者は次のことを認識しておく必要があると思います

  1. これは、ビジネス ルール (最大 10 注文) を実際に強制するものではありません。これが高すぎる金額を避けるための単なる「ある」数であり、時々 12 の注文があったとしても気にしないのであれば、これで問題ないかもしれません。しかし、そうでない場合は、すでに 9 つの注文があり、同じ顧客の注文が 2 つの異なるセッション/トランザクションから同時に挿入されるシナリオを考えてみてください。その場合、このオーバーフロー状況を検出せずに、11 の注文が発生することになります。したがって、実際にはこのトリガーに頼ることはできません。
  2. それに加えて、fk1_customer_id が更新される可能性がある場合は、更新時にこのトリガーを起動する必要があるかもしれません (最初に NULL が FK 列に入れられ、後で実際の値に更新される実装を見てきました)。このシナリオが現実的かどうかを検討することをお勧めします。
  3. トリガーに根本的な欠陥があります。あなたはトランザクションの中にいて、現在実行中だがまだ完了していないステートメントの中にいます。では、挿入が単一の行の挿入ではなく insert into placed_order (select ... from waiting_orders ...) 、トリガーが何を期待するかのようなものである場合はどうなるでしょうか?

この種のビジネス ルールを適用するのは簡単ではありません。ただし、トリガーで実行することを選択した場合は、after ステートメント トリガーで実行することをお勧めします (したがって、before 行トリガーでは実行しません)。after ステートメント トリガーでは、コミットされていない他のトランザクションの結果は表示されませんが、少なくとも現在のステートメントは定義された状態にあります。

実際、ビジネス ルールは基本的にコミット時にのみ適用できます。しかし、Oracle データベースには ON-COMMIT トリガーのようなものはありません。あなたができることは、レコードの数を顧客テーブルに非正規化し (列 ORDER_COUNT を追加)、そのテーブルに遅延制約 (ORDER_COUNT <= 10) を配置することです。ただし、コード全体でこのフィールドを正しく維持することに依拠しています。

完全に信頼できる代替手段ですが、多少面倒ですが、マテリアライズド ビュー (placed_order テーブルで のようなもの) を作成し、マテリアライズド ビューSELECT fk_customer_id, count(*) order_count from placed_orders group by fk_customer_idFAST REFRESH ON COMMITチェック制約 order_count <= 10 を作成することです。これは、このタイプのただし、FAST REFRESH ON COMMIT はコミットの速度を低下させることに注意してください; したがって、このソリューションは大量には使用できません (ため息... なぜ Oracle はON COMMIT トリガーを提供します...)

于 2014-03-21T12:00:16.823 に答える