我正在研究以下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
内运行所有命令?
答案 0 :(得分:2)
您必须在提出错误之前提交INSERT
- 语句。
修改强>
正如其他人已经说过的那样,你不应该也不能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;
/