我正在尝试创建这个简单的触发器:
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);
COMMIT;
END;
/
执行时将结果显示为:
Trigger created
但是当我更新我的表时,会得到以下结果:
update empcopy
set salary=salary+5000;
执行后:
error at line 1
ORA-0498:triiger 'HR.MY_TRIG' is invalid and failed re-validation.
答案 0 :(得分:0)
如果COMMIT
块中没有使用PRAGMA AUTONOMOUS_TRANSACTION
,则无法DECLARE
。
如果数据库允许在行级触发器中提交,则可以在评估其他行之前在一个语句中提交部分行,并将该语句作为一个单元中断 - 单个语句中的所有行都应完成其更改并且共同承诺。
如果您在此触发器中使用AUTONOMOUS_TRANSACTION,这将允许触发器在事务中执行新的UPDATE
,DELETE
等,而不依赖于打开事务中的其他活动DML更改。 />
但请注意,在您的情况下,您的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
,因为DELETE
都会有NULL
:NEW.EID
。如果不打算记录AFTER DELETE
,或者通过DELETE
声明单独处理DELETE
,我建议删除CASE WHEN DELETING
。
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.