트리거에서 INSERT ~ SELECT 에 대한 MUTATING ERROR 해결책이 있나요? 1 6 6,279

by 일조가내꿈 [2013.12.12 14:10:57]


--* 테이블

CREATE TABLE TEMP_OH(TEMP1 VARCHAR2(10),TEMP2 VARCHAR2(10));


--------------------------------------------------------------

--* 트리거 생성

CREATE OR REPLACE TRIGGER TRG_TEMP_OH
    BEFORE INSERT ON TEMP_OH FOR EACH ROW
DECLARE
    VC_TEMP VARCHAR2(1000);
BEGIN

        BEGIN
            SELECT TEMP1
              INTO VC_TEMP
              FROM TEMP_OH A
             WHERE ROWNUM < 2   -- INSERT 바로전에 들어간 행 보려고할때
            ;
           
            EXCEPTION WHEN NO_DATA_FOUND THEN
                 VC_TEMP := NULL;
        END;
       

END TRG_TEMP_OH;
/

이렇게 했는데요,...

INSERT INTO TEMP_OH(TEMP1,TEMP2) VALUES('1','2');

위 문장을 실행하면 괜찮지만


INSERT INTO TEMP_OH(TEMP1,TEMP2)
SELECT '1','2' FROM DUAL; 

요런식으로 하면
MUTATING ERROR 가 나더군요,,

원래는 AFTER-FOR EACH ROW 트리거 였으나,
AFTER 는 트리거에서 자신 테이블을 참조하면 MUTATING ERROR  에러가 나서

BEFORE 방식으로 했으나
역시 INSERT ~ SELCT 식의 INSERT 문장은 어김없이 오류가 나네요 ㅜㅜ

왜 오류가 날까요?
해결책이 있을까요? ㅜㅜ

트리거  안에서 PRAGMA AUTONOMOUS_TRANSACTION; 선언하여
트렌젝션을 분리시키면 될 듯 하나 이또한 트렌젝션이 분리되서 SELECT 에서 잘못된 값을 보고 있을거 같고요,,
by 마농 [2013.12.12 14:32:32]

보통 이런 질문 올라올 때 유형이
1. 실제로 테이블 조회가 필요 없는데도 조회를 하는 경우가 대체로 많았구요.
-> 이경우는 실제 코드를 보고 판단해야 하는 문제이구요.(예시자료만 봐서는 판단이 안서네요.)
2. 실제로 조회가 필요한 경우로 나뉘는데요.
-> 이경우는 복잡한 과정을 거쳐야만 합니다.
아래는 요새 올라온 트리거 관련 글
http://oracleclub.com/article/61280


by 일조가내꿈 [2013.12.12 14:38:10]
답변 감사합니다~

말씀하신 해당 글을 읽고 마농님이 잘 아시는거 같아 질문 올렸었는데
뜻 밖에도 마농님이 다시 답변을 달아 주셨네요 ^^ 감사합니다~

해당 글 내용처럼
패키지를 사용해서 하는 방법도 해서 해보았습니다,,
다만 그렇게 하면 부담 스럽더라구요...
before 트리거 2, after 트리거 1개가 우선순위도 정확히 떨어지갈도 의심스럽고요,

그래서 방법을 찾고 있었어요..ㅜㅜ


그리고 트리거 내에서 자신테이블을 다시 select 는 반드시 필요해요 ㅜㅜ

해당 row - 1 ...
즉 바로 전행의 컬럼값을 읽어 insert 되는 시점에 해당 컬럼을 재가공하여 insert 해야 하거든요...


도움 주셔서 감사합니다~

by 마농 [2013.12.12 14:42:10]
트리거에서 하지 말고 인서트 문장에서 하면 어떨까요?
모든 것은 실제 요구사항과 작성하신 코드를 봐야지만 판단 가능한 것들이네요.
일반적인 방법으로는 트리거에서는 안된다고밖에....

by 일조가내꿈 [2013.12.12 15:25:31]
네, 결국엔 소스내에 INSERT 문장에서 처리해야 할듯 해요 ㅜㅜ

INSERT 되는 소스가 엄청 많아서 고치기 힘들거든요....

트리거 되면 좋았으련만 안타까움만이 ㅎㅎ

by Oracler [2013.12.12 16:29:32]
트리거내에서 트리거 대상이 되는 테이블에 쿼리나 DML을 하면 mutating table 관련 에러가 뜹니다. 이유는 트리거 도중에 현재 변경되는 즉 mutating 중인 테이블을 질의 또는 DML을 하게 되면 데이터 일관성에 문제가 생기기 때문입니다. 즉, INSERT 되기 전의 테이블을 쿼리해야 할까요? INSERT 된 후의 내용을 쿼리해야 할까요?

쉬운 방법은 별도의 테이블을 하나 더 만드는 것입니다. 예를 들어 트리거 내에서 A 테이블의 C1 컬럼에 대한 합계를 질의할 필요가 있다고 할 때 새로운 B 테이블을 만들고 B 테이블은 A 테이블의 C1 컬럼에 대한 합계를 저장하게 한 뒤 트리거에서 B 테이블을 질의하면 됩니다. 이렇게 하면 트리거는 A 테이블에 걸리지만 트리거 내부에서 질의는 B 테이블에 대해 이루어지기 때문에 Mutating 문제를 해결할 수 있습니다. 단점은 두 개의 테이블을 유지 관리해야 하는 점이죠.

또는 Orable 11g 이후 버전의 경우 Compound Trigger를 이용하면 해결 가능합니다.

by 일조가내꿈 [2013.12.12 19:07:07]
답변 감사합니다~
임시테이블도 또다른 방안이었네요 ㅎㅎ

Compound Trigger 란것도 있었군요~
다만 9i 라 힘들다는,,,ㅎㅎ

많이 배운거 같습니다, 감사합니다~
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입