본문 바로가기

Oracle

Oracle Trigger 사용시 Mutating 오류가 발생하면.


개발 도중 실시간 데이터를 DB에 저장 하고  통계를 위하여 실시간 데이터에서 10분 평균을 저장할 테이블이 필요해졌다.

제일 편한 방법이 트리거라고 생각하여 작성했는데...

두둥! 트리거 안에서는 해당 트리거가 동작하는 테이블을 억세스 할수 없는것이었다.

여기 저기 뒤져보니 row 단위로 동작하는 트리거(FOR EACH ROW 구문이 들어간...)는 불가능 하고

Statement 트리거는 트랜잭션이 끝난 후 동작하는 트리거라 될거라는 거다

인터넷에서 참조하는 트리거는 패키지 테이블을 만들어서 구성하라고 했지만... 내 능력으로는 에러만 나서... ㅠㅠ

임시 테이블을 이용하여 작업을 했다

결과는 성공.


참고를 위해 소스를 남긴다.

DROP TRIGGER FC.REALDATAINT_BFRW_TR;

CREATE OR REPLACE TRIGGER FC.REALDATAINT_BFRW_TR
BEFORE DELETE OR INSERT OR UPDATE ON FC.REALDATAINT FOR EACH ROW
DECLARE
    v_meascd   REALDATAINT.MEASCD%TYPE;
    v_measymds REALDATAINT.MEASYMDS%TYPE;
BEGIN

    v_meascd   := :NEW.MEASCD;
    v_measymds := :NEW.MEASYMDS;
   
    IF (LENGTH(:OLD.MEASCD) = 9) THEN
        v_meascd   := :OLD.MEASCD;
        v_measymds := :OLD.MEASYMDS;
    END IF;

    DELETE FROM REALDATAINT_TRTMP;
    INSERT INTO REALDATAINT_TRTMP (MEASCD, MEASYMDS) VALUES (v_meascd, v_measymds);
   
   
END;
/


* 임시 테이블에 데이터를 넣는 트리거이며 insert, update, delete때 모두 동작해야 한다.
위 구문 중 BEFORE DELETE.... 구문을 AFTER DELETE... 구문으로 사용하면 DELETE 실행 후 동작하게 되어 키 값을 받아올수 없게 된다.
delete 시에도 동작하게 하려면 꼭 BEFORE를 사용하자.

------

DROP TRIGGER FC.REALDATAINT_AFST_TR;

CREATE OR REPLACE TRIGGER FC.REALDATAINT_AFST_TR
AFTER INSERT OR UPDATE OR DELETE ON FC.REALDATAINT
DECLARE
    v_meascd   REALDATAINT.MEASCD%TYPE;
    v_measymds REALDATAINT.MEASYMDS%TYPE;
   
    CURSOR cur_select IS
    SELECT MEASCD, MEASYMDS FROM REALDATAINT_TRTMP;
BEGIN
   
    OPEN cur_select;
    LOOP
        FETCH cur_select INTO v_meascd, v_measymds;
        EXIT WHEN cur_select%NOTFOUND;
       
        DELETE FROM FCS_REALDATAINT_MIN   WHERE MEASCD = v_meascd AND MEASYMDS = SUBSTR(v_measymds,1,12);
        DELETE FROM FCS_REALDATAINT_HOUR  WHERE MEASCD = v_meascd AND MEASYMDS = SUBSTR(v_measymds,1,10);
        DELETE FROM FCS_REALDATAINT_DAY   WHERE MEASCD = v_meascd AND MEASYMDS = SUBSTR(v_measymds,1,8);
        DELETE FROM FCS_REALDATAINT_MONTH WHERE MEASCD = v_meascd AND MEASYMDS = SUBSTR(v_measymds,1,6);

        INSERT INTO FCS_REALDATAINT_MIN
               (
                MEASCD,
                MEASYMDS,
                MEASNVAL
               )
               VALUES
               (v_meascd,
                SUBSTR(v_measymds,1,11)||'0',
                (SELECT ROUND(NVL(AVG(MEASNVAL),0),2)
                  FROM  REALDATAINT
                  WHERE MEASCD = v_meascd AND MEASYMDS LIKE SUBSTR(v_measymds,1,11)||'%')
               );
              
        INSERT INTO FCS_REALDATAINT_HOUR
               (
                MEASCD,
                MEASYMDS,
                MEASNVAL
               )
               VALUES
               (v_meascd,
                SUBSTR(v_measymds,1,10),
                (SELECT ROUND(NVL(AVG(MEASNVAL),0),2)
                  FROM  REALDATAINT
                  WHERE MEASCD = v_meascd AND MEASYMDS LIKE SUBSTR(v_measymds,1,10)||'%')
               );

        INSERT INTO FCS_REALDATAINT_DAY
               (
                MEASCD,
                MEASYMDS,
                MEASNVAL
               )
               VALUES
               (v_meascd,
                SUBSTR(v_measymds,1,8),
                (SELECT ROUND(NVL(AVG(MEASNVAL),0),2)
                  FROM  REALDATAINT
                  WHERE MEASCD = v_meascd AND MEASYMDS LIKE SUBSTR(v_measymds,1,8)||'%')
               );
              
        INSERT INTO FCS_REALDATAINT_MONTH
               (
                MEASCD,
                MEASYMDS,
                MEASNVAL
               )
               VALUES
               (v_meascd,
                SUBSTR(v_measymds,1,6),
                (SELECT ROUND(NVL(AVG(MEASNVAL),0),2)
                  FROM  REALDATAINT
                  WHERE MEASCD = v_meascd AND MEASYMDS LIKE SUBSTR(v_measymds,1,6)||'%')
               );                                            
    END LOOP;
   
END;
/


*  임시 테이블의 내용을 반영하는 트리거.

끗.



'Oracle' 카테고리의 다른 글

Oracle 가상의 테이블을 만드는 방법  (0) 2010.08.19