1. 程式人生 > >oracle變異表觸發器中ORA-04091錯誤原因及解決方案

oracle變異表觸發器中ORA-04091錯誤原因及解決方案

變異表是指激發觸發器的DML語句所操作的表

當對一個表建立行級觸發器時,有下列兩條限制:

1.不能讀取或修改任何觸發語句的變異表; 2.不能讀取或修改觸發表的一個約束表的PRIMARY

  KEY,UNIQUE 或FOREIGN KEY關鍵字的列, 但

 可以修改其他列

例如:有這樣一個需求:在更新員工所在部門或向部門插入新員工時,部門中員工人數不超過7人

如果按照下面的觸發器寫就會使UPDATE操作時報錯

CREATE OR REPLACE TRIGGER updatetrigger
BEFORE UPDATE ON EMP
FOR EACH ROW
DECLARE
  v_num NUMBER;
BEGIN
  SELECT count(*) INTO v_num FROM emp
  WHERE deptno = :new.deptno;
  IF (v_num > 7) THEN
    RAISE_APPLICATION_ERROR(-20001,
                            '員工數多於'||v_num);  
  END IF;
END updatetrigger;

ORA-04091: 表 SCOTT.EMP 發生了變化, 觸發器/函式不能讀它
ORA-06512: 在 "SCOTT.UPDATETRIGGER", line 4
ORA-04088: 觸發器 'SCOTT.UPDATETRIGGER' 執行過程中出錯

如果既想更新變異表,同時又需要查詢變異表,那麼如何處理呢?

將行級觸發器與語句級觸發器結合起來,在行級觸發器中獲取要修改的記錄的資訊,存放到一個軟體包的全域性變數中,然後在語句級後觸發器中利用軟體包中全域性變數資訊對變異表的查詢,並根據查詢的結果進行業務處理

例如:

為了實現在更新員工所在部門或向部門插入新員工時,部門中員工人數不超過7人,可以在emp表上建立兩個觸發器,同時建立一個共享資訊的包

CREATE OR REPLACE PACKAGE mutate_pkg 
AS
  v_deptno NUMBER(2); 
END;

CREATE OR REPLACE TRIGGER  rmutate_trigger
BEFORE INSERT OR UPDATE OF deptno ON EMP 
FOR EACH ROW
BEGIN
  mutate_pkg.v_deptno:=:new.deptno;  
END; 

CREATE OR REPLACE TRIGGER smutate_trigger
AFTER INSERT OR UPDATE OF deptno ON EMP
DECLARE
  v_num number(3);
BEGIN
  SELECT count(*) INTO v_num FROM emp 
  WHERE deptno = mutate_pkg.v_deptno;
  IF v_num>7 THEN
    RAISE_APPLICATION_ERROR(-20003,'這部門的員工太多了 '||
                            mutate_pkg.v_deptno);
  END IF;
END; 

這樣操作,就不會報ORA-04091: 表SCOTT.EMP 發生了變化,觸發器/函式不能讀它錯誤了