Trigger 실행시 Ora-04091:Mutation error 처리방법
작성자 관리자 작성시간 2008-01-10 13:28:22
 

Trigger 실행시 Ora-04091:Mutation error 처리방법 


예를들어 emp Table에 Insert/Update/Delete 될때마다 부서별 평균급여 Table에 Update 한다고 가정했을때 이때 사용자가 emp Table에 변경이 가해 졌을때 emp Table에 어떠한 처리를 하는 Trigger를 만든다면 원치않은 결과가 나올수가 있겠죠.
그래서 Oracle은 emp Table에 row Trigger를 만들면 원천적으로 emp Table을 아예 Access할수 없게 하며 이와 같은 원칙에 위배될때 mutationg error가 발생하게 된다.

해결책은 Statement trigger로 만들던지 PL/SQL Table을 생성하여 해결하는 방법이 있다. Statement Trigger 인 경우에는 :new.column, :old.column의 사용은 불가능하다. 여기서는 후자로 해결해보자.

emp Table의 LayOut은 아래와 같다.
SQL>desc emp
  NAME                      NULL?            TYPE
  ------------------------------------------------
  empno
  ename
  job
  mgr
  sal
  deptno

SQL>desc dept
  NAME                      NULL?            TYPE
  ------------------------------------------------
  deptno
  dname
  loc
  sal

1. PL/SQL Table을 생성한다.
create or replace package emp_pkg as
  type  emp_tab_type is table of emp.deptno%type index by
        binary_integer;
  emp_old  emp_tab_type;
  emp_new  emp_tab_type;
  emp_index binary_integer;
end emp_pkg;

2. Before statement Trigger를 생성한다.
create or replace trigger emp_bef_stm_all
      before insert or update or delete on emp
begin
emp_pkg.emp_index  := 0;
end;
/

3. After row Trigger를 생성한다.
create or replace trigger emp_aft_row_all
      after insert or update or delete on emp
      for each row
begin
emp_pkg.emp_index    := emp_pkg.emp_index + 1;
emp_pkg.emp_old(emp_pkg.emp_index) := :old.deptno;
emp_pkg.emp_new(emp_pkg.emp_index) := :new.deptno;
end;
/

4. After Statement Trigger를 생성
create or replace trigger emp_aft_atm_all
      after insert or update or delete on emp
      for each row
declare
v_sal  emp.sal%type;
begin
for i in 1..emp_pkg.emp_index loop
    select avg(sal) into v_sal from emp
    where deptno = emp_pkg.emp_old(i);

    update dept set sal = v_sal
    where deptno = emp_pkg.emp_old(i);

    dbms_output.put_line('DEPTNO(old)=>'||to_char(emp_pkg.emp_old(i)));

    if emp_pkg.emp_new(i) != emp_pkg.emp_old(i) then
        select avg(sal) into v_sal from emp
        where deptno = emp_pkg.emp_new(i);

        update dept set sal = v_sal
        where deptno = emp_pkg.emp_new(i);

        dbms_output.put_line('DEPTNO(NEW)=>'||to_char(emp_pkg.emp_NEW(i)));
    end if;
end loop;
emp_pkg.emp_index := 0;
end;
/

5. 확인
SQL>update emp set sap = 90000
  where empno = 1111;

SQL>
  DEPTNO(old)=>20
  1 row updated.


목록 | 입력 | 수정 | 답변 | 삭제