触发RAISE_APPLICATION_ERROR但执行内部命令

时间:2013-12-02 11:45:16

标签: oracle exception plsql triggers

我正在研究以下PL / SQL trigger

CREATE OR REPLACE TRIGGER trigger_1
BEFORE UPDATE ON worker
FOR EACH ROW
DECLARE
BEGIN
  IF :OLD.type = 'PRESIDENT' THEN
    INSERT INTO trigger_log VALUES (sysdate, 'Nope.', 'No change.');
    RAISE_APPLICATION_ERROR(-20111, 'Can not change!');
  END IF;
END;

在这里,当UPDATE的{​​{1}}即将发生变化时,我想取消worker表上的PRESIDENT命令。同时,我希望将此命令记录到名为payment的表中。问题是,当我trigger_log UPDATE被取消,但是日志记录(RAISE_APPLICATION_ERROR)也是如此。我如何INSERT INTO trigger_log或抛出RAISE_APPLICATION_ERROR,但仍然可以在EXCEPTION内运行所有命令?

3 个答案:

答案 0 :(得分:2)

您必须在提出错误之前提交INSERT - 语句。

想想AUTONOMOUS_TRANSACTION

修改
正如其他人已经说过的那样,你不应该也不能commit在触发器内(异常自治事务)。所以考虑使用Tom Thomas的解决方案或调用logging-procedure / -package。

答案 1 :(得分:1)

您可以从触发器中调出stored procedure。该存储过程应声明为PRAGMA AUTONOMOUS_TRANSACTION。试试这样,

    CREATE OR REPLACE 
    PROCEDURE log_error_p
    AS
         PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
         INSERT INTO trigger_log VALUES (SYSDATE, 'Nope.', 'No change.');
         COMMIT;
    END;

-

   CREATE OR REPLACE TRIGGER trigger_1
    BEFORE UPDATE ON worker
    FOR EACH ROW
    DECLARE
    BEGIN
         IF :OLD.TYPE = 'PRESIDENT' THEN
              log_error_p();
         RAISE_APPLICATION_ERROR(-20111, 'Can not change!');
         END IF;
    END;
    /

答案 2 :(得分:-1)

首先,永远不要在触发器内使用提交或回滚。这是一个编码标准。至于你的问题,我认为这比raise_application_error

更好
CREATE OR REPLACE TRIGGER trigger_1
BEFORE UPDATE ON worker
REFERENCING OLD as o AND NEW as n
FOR EACH ROW
DECLARE
     InsertException EXCEPTION;
BEGIN
     IF o.TYPE = 'PRESIDENT' THEN
          RAISE InsertException;
     END IF;
EXCEPTION
     WHEN InsertException THEN
     INSERT INTO trigger_log VALUES (SYSDATE, 'Nope.', 'No change.');
     DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/