如果不在DECLARE
区块中使用PRAGMA AUTONOMOUS_TRANSACTION
,则不能使用COMMIT
。
如果数据库允许在行级触发器中提交,则可以在其他语句被评估之前提交语句中的部分行,并将该语句作为一个单元进行中断 - 单个语句中的所有行应完成其更改并一起承诺。
如果您要在此触发器中使用AUTONOMOUS_TRANSACTION,这将允许触发器在独立于打开事务中的其他活动DML更改的事务中执行新的UPDATE
s,DELETE
s等。
不过需要注意,在你的情况下,你的TRIGGER
实际上并不执行任何突变DML
,甚至也没有任何读取,所以你并不需要一个COMMIT
可言。你所需要做的就是放下你的COMMIT
,如下所示。
CREATE OR REPLACE TRIGGER my_trig
BEFORE DELETE OR INSERT OR UPDATE ON empcopy
FOR EACH ROW
WHEN (NEW.EID > 0)
DECLARE
sal_diff number;
BEGIN
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' || :OLD.salary);
dbms_output.put_line('New salary: ' || :NEW.salary);
dbms_output.put_line('Salary difference: ' || sal_diff);
END;
/
但是我会提出一些其他的改变。
由于其他触发器也可以更改NEW
值,因此可以考虑将其设置为AFTER TRIGGER
,以仅记录最终状态。
此触发器也不会记录任何DELETE
s,因为DELETE
s将全部具有NULL
:NEW.EID
。如果日志记录DELETE
s没有打算,或者通过CASE WHEN DELETING
声明单独处理DELETE
,我建议删除AFTER DELETE
。
CREATE OR REPLACE TRIGGER MY_TRIG
AFTER DELETE OR INSERT OR UPDATE ON EMPCOPY
FOR EACH ROW
DECLARE
SAL_DIFF NUMBER;
BEGIN
CASE WHEN DELETING
THEN
DBMS_OUTPUT.put_line('Log the delete here if you want.');
WHEN (:NEW.EID > 0)
THEN
SAL_DIFF := COALESCE(:NEW.SALARY, 0) - COALESCE(:OLD.SALARY, 0);
DBMS_OUTPUT.put_line('Old salary: ' || :OLD.SALARY);
DBMS_OUTPUT.put_line('New salary: ' || :NEW.SALARY);
DBMS_OUTPUT.put_line('Salary difference: ' || SAL_DIFF);
ELSE NULL;
END CASE;
END;
/
另外DBMS_OUTPUT是瞬态记录。如果您想更长期记录EMPCOPY
的更改记录,Oracle提供了可用于自动化和控制数据变更跟踪的工具,例如审计追踪和FGA。
编辑:下面的例子。
创建一个测试表:
CREATE TABLE EMPCOPY(
EID NUMBER NOT NULL,
SALARY NUMBER
);
Table EMPCOPY created.
然后创建触发器:
CREATE OR REPLACE TRIGGER MY_TRIG
AFTER DELETE OR INSERT OR UPDATE ON EMPCOPY
FOR EACH ROW
DECLARE
SAL_DIFF NUMBER;
BEGIN
CASE WHEN DELETING
THEN
DBMS_OUTPUT.put_line('Log the delete here if you want.');
WHEN (:NEW.EID > 0)
THEN
SAL_DIFF := COALESCE(:NEW.SALARY, 0) - COALESCE(:OLD.SALARY, 0);
DBMS_OUTPUT.put_line('Old salary: ' || :OLD.SALARY);
DBMS_OUTPUT.put_line('New salary: ' || :NEW.SALARY);
DBMS_OUTPUT.put_line('Salary difference: ' || SAL_DIFF);
ELSE NULL;
END CASE;
END;
/
Trigger MY_TRIG compiled
然后对其进行测试:
SQL> --Should not log, EMPID is not greater than zero.
SQL> INSERT INTO EMPCOPY VALUES (-13, 50000);
1 row inserted.
SQL> --Should log, EMPID is greater than zero.
SQL> INSERT INTO EMPCOPY VALUES (1919, 75000);
Old salary:
New salary: 75000
Salary difference: 75000
1 row inserted.
SQL> -- The statement you provided. This should log for EMPID=1919 but not EMPID=-13
SQL> update empcopy
2 set salary=salary+5000;
Old salary: 75000
New salary: 80000
Salary difference: 5000
2 rows updated.
SQL> -- This should log a PLACEHOLDER value for each row on delete.
SQL> DELETE FROM EMPCOPY;
Log the delete here if you want.
Log the delete here if you want.
2 rows deleted.
貌似有一个非常类似的问题:HTTP: //stackoverflow.com/questions/22668507/oracle-trigger-ora-04098-trigger-is-invalid-and-failed-re-validation – Debangshu
不适用此解决方案。 –
@Jaskunwarsingh这个答案已经更新了一个完整的工作示例。请运行提供的示例,并告诉我是否收到错误。还包括你的oracle版本通常是有帮助的。 – alexgibbs