트리거에서 ORA-04091 이 발생했습니다. 어떻게 해야하죠~~ 0 6 4,542

by 손님 [PL/SQL] trigger [2009.09.23 17:56:56]


 

트리거를 아래와 같이 작성했습니다.

안에 있는 Query는 독자적으로 잘 동작합니다.

문제는 SUPPORT_WORK_N  테이블에 트리거를 걸어서...

insert, update시 해당 support_work_n에서 데이터를 읽어 다른 테이블에 넣고자 합니다.

근데... 이때... 04091 오류가 발생합니다. 즉... 해당 테이블이 변경이 되어서 트리거를 동작할 수 없다는건데...

해당 테이블을 수정하는게 아니라.. 단지 읽기만을 위한것인데도.. 오류가 발생하네요...

어떤 방법을 써야할지....

도움을 요청합니다.

아래는 제가 사용한 트리거 입니다.

 

DROP TRIGGER KPEA.TRG_CPD_APPLY;

CREATE OR REPLACE TRIGGER KPEA.TRG_CPD_APPLY
AFTER DELETE OR INSERT OR UPDATE
ON KPEA.SUPPORT_WORK_N
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
DECLARE
tmpVar NUMBER;
BEGIN
   
    -- INSERT AND APPROVAL_GB : DB구축에서 작업할 경우
    -- UPDATE AND APPROVAL_GB : 관리자 승인의 경우
    IF (( INSERTING OR UPDATING ) AND :NEW.APPROVAL_GB = 'Y' ) THEN
        DBMS_OUTPUT.PUT_LINE('===================================================');   
        IF(INSERTING) THEN
          DBMS_OUTPUT.PUT_LINE('Inserting .... : ' || :NEW.human_id);    
        ELSIF (UPDATING) THEN
          DBMS_OUTPUT.PUT_LINE('Updating .... : ' || :NEW.human_id);    
        END IF;
        DBMS_OUTPUT.PUT_LINE('===================================================');
       
      merge into cpd_record_tb_all tar
      using (
          select rnum sequence_no, human_id, 'SUPPORT_WORK_N' BIRTH_TABLE, '실무경력' cpd_name, disp_mon || ' 실무경력' cpd_content, point, startdate start_date, enddate end_date,
          '' sponsor_code, '' sponsor_name, mon_count real_unit, 2 weight_cost, sysdate reg_date, sysdate mod_date, date_mon remark
          from ( 
              select row_number() over(partition by human_id order by date_mon) rnum, human_id, date_mon, disp_mon, startdate, enddate, mon_count, 2 * round(mon_count / lastday, 6) point from (
                  -- human_id별 / 월별 실무경력 일수(업무를 수행한 날짜 수)
                  select human_id, to_char(datex, 'yyyy-mm') date_mon, to_char(datex, 'yyyy"년" mm"월"') disp_mon, min(datex) startdate, max(datex) enddate, count(human_id) mon_count, to_number(to_char(last_day(datex), 'dd')) lastday from (
                      -- human_id 별 날짜(경력 수행일)별 건수....
                      select human_id, datex  , count(human_id) cnt from (
                          -- human_id별 기산일에 포함된 실무경력 조회(실무경력 날짜를 기산일 내로 변경하여 처리함)
                          select a.human_id, greatest(a.d_startdate, b.start_date) pstart, LEAST(a.d_enddate, b.end_date) pend
                          from
                              (
                                  -- 기산일 계산을 위한 기준일 정보 조회
                                  select human_id, d_startdate, d_enddate from cpd_reckoning_initial where  human_id = :NEW.human_id
                              ) a,
                              (
                                  -- human_id 별 실무 경력 조회
                                  select human_id, work_name,
                                          decode(length(start_date), 4, start_date || '01-01', 7, start_date || '-01', start_date) start_date,
                                          decode(length(nvl(end_date, to_char(sysdate, 'yyyy-mm-dd'))), 4, end_date || '01-31', 7, to_char(last_day(to_date(end_date || '-01')), 'yyyy-mm-dd'), end_date) end_date
                                  from support_work_n
                              ) b
                          where a.human_id = b.human_id and b.end_date between d_startdate and d_enddate
                          order by human_id, start_date
                      ) , dateseq
                      where datex between pstart and pend
                      group by human_id, datex
                      order by human_id, datex
                  )
                  group by human_id, to_char(datex, 'yyyy-mm'), to_char(datex, 'yyyy"년" mm"월"'), to_number(to_char(last_day(datex), 'dd'))
                  order by human_id, date_mon
              )
          )
      ) src
      on (tar.birth_table = 'SUPPORT_WORK_N'
          and src.human_id = tar.human_id
          and tar.remark = src.remark )
      when matched then
          update set  tar.sequence_no     = src.sequence_no,
                      tar.cpd_name        = src.cpd_name,
                      tar.cpd_content     = src.cpd_content,
                      tar.point           = src.point,
                      tar.start_date      = src.start_date,
                      tar.end_date        = src.end_date,
                      tar.sponsor_code    = src.sponsor_code,
                      tar.sponsor_name    = src.sponsor_name,
                      tar.real_unit       = src.real_unit,
                      tar.weight_cost     = src.weight_cost,
                      tar.mod_date        = sysdate
      when not matched then
          insert (tar.sequence_no, tar.human_id, tar.BIRTH_TABLE, tar.cpd_name, tar.cpd_content, tar.point, tar.start_date, tar.end_date, tar.sponsor_code, tar.sponsor_name, tar.real_unit, tar.weight_cost, tar.reg_date, tar.mod_date, tar.remark)
          values (src.sequence_no, src.human_id, src.BIRTH_TABLE, src.cpd_name, src.cpd_content, src.point, src.start_date, src.end_date, src.sponsor_code, src.sponsor_name, src.real_unit, src.weight_cost, src.reg_date, src.mod_date, src.remark)
      ;
         
   
    END IF;                          
   
    IF ( DELETING ) THEN
        DBMS_OUTPUT.PUT_LINE('===================================================');   
        DBMS_OUTPUT.PUT_LINE('Deleting ....');    
        DBMS_OUTPUT.PUT_LINE('===================================================');   
   
    END IF;   
END TRG_CPD_APPLY;
/

 

by 마농 [2009.09.23 19:34:24]
행트리거에서는 변경중인 해당 테이블을 참조하는것이 원칙적으로 안됩니다.

by 마농 [2009.09.23 19:57:04]
소스를 자세히 살펴보니 해당 테이블에서 조회해오는 내용이 별거 없네요.
자료를 Select 할 필요 없이 바로 :new.컬럼명 으로 참조하시면 됩니다.

by 홍서방 [2009.09.23 20:22:03]
:new. 로 하게되면 해당 trigger 가 발생한 Row 하나만 조회할 수 있습니다. 여기서 원하는 것은 해당 Row와 연관성있는 다른 여러 Row들을 읽고자 함이기에.... 위와 같은 Query를 만들게 되었습니다~~~

by 마농 [2009.09.24 08:13:02]
위 방법으로는 안됩니다.
다른 방법을 검색해서 찾아보세요.
위 에러를 피해가는 방법이 있긴한데 상당히 복잡합니다.


by 김우열 [2009.09.25 11:49:35]
해당테이블을 읽을때 뷰로 읽으면 가능한 것인가요? 저두 안해봐서 모르겠네요.. 음.. 테스트 함 해볼까나... ㅡㅡ;
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입