SQL错误:ORA-04091:表正在变异,触发器/函数可能看不到它

时间:2018-05-05 02:02:46

标签: sql oracle plsql database-trigger

当我更新表中的数据时,我收到'SQL错误:ORA-04091:表正在变异,触发器/函数可能看不到它。

DDL:

CREATE TABLE STUDENT_DIM (STUD_ID NUMBER,CURR_STUD_NAME VARCHAR2(30),PREV_STUD_NAME VARCHAR2(30), CURR_DOJ DATE, PREV_DOJ DATE, CURRR_DEPT_NAME VARCHAR2(30),PREV_DEPT_NAME VARCHAR2(30));
INSERT INTO STUDENT_DIM(STUD_ID,CURR_STUD_NAME,CURR_DOJ,CURRR_DEPT_NAME) VALUES(1,'VINOTH','01-AUG-2017','CSE');
INSERT INTO STUDENT_DIM(STUD_ID,CURR_STUD_NAME,CURR_DOJ,CURRR_DEPT_NAME) VALUES(2,'SURESH','11-SEP-2017','ECE');
INSERT INTO STUDENT_DIM(STUD_ID,CURR_STUD_NAME,CURR_DOJ,CURRR_DEPT_NAME) VALUES(3,'RAM','01-MAY-2018','IT');

触发:

CREATE OR REPLACE TRIGGER STUDENT_DIM_HIST BEFORE UPDATE ON STUDENT_DIM FOR EACH ROW
BEGIN
CASE WHEN UPDATING('CURR_STUD_NAME') THEN UPDATE STUDENT_DIM SET PREV_STUD_NAME = :OLD.CURR_STUD_NAME WHERE STUD_ID = :OLD.STUD_ID;
     WHEN UPDATING('CURR_DOJ')       THEN UPDATE STUDENT_DIM SET PREV_DOJ = :OLD.CURR_DOJ WHERE STUD_ID = :OLD.STUD_ID;
     WHEN UPDATING('CURRR_DEPT_NAME') THEN UPDATE STUDENT_DIM SET PREV_DEPT_NAME = :OLD.CURRR_DEPT_NAME WHERE STUD_ID = :OLD.STUD_ID;
END CASE;
END;

更新

UPDATE STUDENT_DIM SET CURR_STUD_NAME = 'RAM KUMAR' WHERE STUD_ID = 3;

2 个答案:

答案 0 :(得分:1)

同一个表的操作(更新)期间,您的触发器会尝试引用拥有触发器的,并且问题会因此而引发。

请改为使用某些作业,如下所示:

CREATE OR REPLACE TRIGGER STUDENT_DIM_HIST BEFORE UPDATE ON STUDENT_DIM FOR EACH ROW
BEGIN
CASE WHEN UPDATING('CURR_STUD_NAME')  THEN :NEW.PREV_STUD_NAME := :OLD.CURR_STUD_NAME;
     WHEN UPDATING('CURR_DOJ')        THEN :NEW.PREV_DOJ       := :OLD.CURR_DOJ;
     WHEN UPDATING('CURRR_DEPT_NAME') THEN :NEW.PREV_DEPT_NAME := :OLD.CURRR_DEPT_NAME;
END CASE;
END;

答案 1 :(得分:0)

当触发器引用拥有触发器的表时,会发生Oracle变异触发器错误,从而导致" ORA-04091:表名发生变异,触发器/函数可能看不到它。"消息。

  1. 不要使用触发器 - 避免变异表错误的最佳方法是不使用触发器。虽然面向对象的Oracle提供了"方法"与表相关联的,除非绝对必要,否则大多数精明的PL / SQL开发人员都会避免使用触发器。

  2. 使用""或"而不是"触发器 - 如果必须使用触发器,最好通过使用""来避免变异表错误。触发,以避免与变异表相关的货币问题。例如,使用触发器":在xxx"上更新后,原始更新已完成,表格不会发生变异。

  3. 重新设计触发器语法 - 避免使用行级和语句级触发器的组合来改变表。

  4. 使用自治事务 - 您可以通过将触发器标记为自治事务来避免变异表错误,使其独立于调用该过程的表。