1

タイムレコーダーをパンチする個人が過去5分以内にカードをパンチしたかどうかをテストすることになっているトリガーがあります。情報がない場合は、テーブルclk_dataに移動するために残しておく必要があります。そうでない場合は、ログテーブルutl_logbookにレコードを作成し、clk_dataへの挿入を中止する必要があります。

私が良いパンチを実行すると、インサートは宣伝どおりに機能します。パンチが悪い場合(最後のパンチから5分以内)、次のエラーが発生します。

SQL Error: ORA-20101: Too Soon
ORA-06512: at "TRUTRACK.INSERT_CLK_DATA", line 14
ORA-04088: error during execution of trigger 'TRUTRACK.INSERT_CLK_DATA'

トランザクションは停止しましたが、utl_logbookに記録されていません。

The trigger code:
create or replace
TRIGGER "INSERT_CLK_DATA" 
BEFORE INSERT ON clk_data 
FOR EACH row 

BEGIN
  DECLARE qty INTEGER := 0;
  BEGIN
    SELECT COUNT(*)
    INTO qty
    FROM clk_data
    WHERE clk_time BETWEEN (:new.clk_time - 5/(24*60)) AND (:new.clk_time + 5/(24*60))
    AND :new.payroll = clk_data.payroll;

    IF qty > 0 THEN

      INSERT INTO utl_logbook (time, source, message) VALUES (sysdate, 'INSERT_CLK_DATA', 'Clock punch within restricted window. Payroll ID:' || :new.payroll || ' Time: ' || :new.clk_time || ' Type: ' || :new.type);

      RAISE_APPLICATION_ERROR(-20101, 'Too Soon');

    END IF;

  END;
END;
4

2 に答える 2

3

これは、を採用できるまれなケースの1つですpragma autonomous_transaction。これにより、メインのトランザクションに影響を与えることなくコミットできます。注意して使用してください。自律型トランザクションautonomous_transactionプラグマの詳細をご覧ください

次に例を示します。

   -- our error logging table 

   create table tb_log(
      msg varchar2(123)
    )
    /

   -- our working table
   create table tb_table(
     col11 number
    )
    /

-- procedure that is going to log errors


NK@XE> create or replace procedure log_error(p_msg in varchar2)
  2    is
  3      pragma autonomous_transaction;
  4    begin
  5      insert into tb_log(msg)
  6        values(p_msg);
  7      commit;
  8    end;
NK@XE> /

Procedure created.

NK@XE> create or replace trigger tr_tb_table
  2    before insert on tb_table
  3    for each row
  4    begin
  5      if mod(:new.col1, 2) != 0
  6      then
  7         log_error('Error!');
  8         raise_application_error(-20000, 'Error has ocurred!');
  9      end if;
 10    end;
 11  /

Trigger created.

NK@XE> select * from tb_log;

no rows selected

NK@XE> select * from tb_table;

no rows selected

NK@XE> insert into tb_table(col1) values(1);

insert into tb_table(col1) values(1)
            *
ERROR at line 1:
ORA-20000: Error has ocurred!
ORA-06512: at "NK.TR_TB_TABLE", line 5
ORA-04088: error during execution of trigger 'NK.TR_TB_TABLE'


NK@XE> select * from tb_log;

MSG
--------------------------------------------------------------------------------
Error!
于 2012-10-09T17:58:57.730 に答える
1

@ nicholas-krasnovが解決策を提供しましたが、その理由を少し詳しく説明します。トリガー本体に例外をスローします。

RAISE_APPLICATION_ERROR(-20101, 'Too Soon');

これにより、トランザクションがロールバックされます。これの完全な詳細は見つけることができます:

http://psoug.org/reference/exception_handling.html

ステートメントが失敗した場合、Oracleはセーブポイントにロールバックします。通常、トランザクション全体ではなく、失敗したSQLステートメントのみがロールバックされます。ただし、ステートメントで未処理の例外が発生した場合、ホスト環境が何をロールバックするかを決定します。

于 2012-10-09T18:43:40.947 に答える