내 문제를 조사했지만 해결 방법이 아직 없으므로 여기에 게시 할 예정입니다. Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production을 사용하고 있습니다.오라클의 Compound Trigger Update에서 오래된 값을 얻는 방법
나는 Main_Table에 10 개의 레코드가 있다고 가정하고 새로운 테이블을 업데이트 할 때 이전 값과 새 값을 로그 (삽입)하는 Log_Table이 있습니다.
나는 "Main_Table"의 모든 열을 동적으로 반복하고 new를 통해 필터링하여 업데이트하는 행 레코드를 얻기 위해 복합 트리거 (변형 오류를 피하기 위해)를 사용하고 있습니다. 기본 키 (UID)).
나는 복합 트리거를 사용하고 싶습니다.
모든 열을 동적으로 반복하고 열 값을 일치시켜야하므로 :old
및 :new
을 사용하지 않습니다.
But it is again giving me mutating error:
Error report -
SQL Error: ORA-04091: table Main_Table is mutating, trigger/function may not see it
ORA-06512: at "Schema.TRG_TEST", line 87
ORA-04088: error during execution of trigger 'Schema.TRG_TEST'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Below is my trigger code:
create or replace TRIGGER TRG_TEST
FOR INSERT or UPDATE ON Main_Table
COMPOUND TRIGGER
TYPE NUMBER_TABLE IS TABLE OF NUMBER;
tblTABLE2_IDS NUMBER_TABLE;
TYPE VARCHAR_TABLE IS TABLE OF VARCHAR(2000);
tblTABLE3_IDS VARCHAR_TABLE;
TYPE VARCHAR_TABLE1 IS TABLE OF VARCHAR(2000);
tblTABLE4_IDS VARCHAR_TABLE1;
vcount NUMBER;
colCount NUMBER;
colCountAfter NUMBER;
vvalue VARCHAR2(4000);
vcolumn VARCHAR2(4000);
sql1 VARCHAR2(4000);
dynamicq varchar(4000);
testv varchar(2000);
testv1 varchar(2000);
ssql varchar(2000);
ssql1 varchar(2000);
maxsiteid NUMBER;
newsid varchar(2000);
newstid varchar(2000);
newuid varchar(2000);
--Executed before DML statement
BEFORE STATEMENT IS
BEGIN
tblTABLE2_IDS := NUMBER_TABLE();
tblTABLE3_IDS:= VARCHAR_TABLE();
tblTABLE4_IDS:= VARCHAR_TABLE1();
IF UPDATING THEN
dbms_output.put_line('Before Statement - In Updating');
--dbms_output.put_line('Before Each Row - In Updating');
-- tblTABLE2_IDS.EXTEND;
--tblTABLE2_IDS(tblTABLE2_IDS.LAST) := :new.UID;
END IF;
END BEFORE STATEMENT;
--Executed before each row change- :NEW, :OLD are available
BEFORE EACH ROW IS
BEGIN
IF UPDATING THEN
dbms_output.put_line('Before Each Row - In Updating');
tblTABLE2_IDS.EXTEND;
tblTABLE2_IDS(tblTABLE2_IDS.LAST) := :new.UID;
-- FOR columnlist IN
--(SELECT COLUMN_NAME AS COLUMN_NAME FROM all_tab_columns WHERE lower(TABLE_NAME) = 'Main_Table'
-- AND lower(COLUMN_NAME) NOT IN ('s_id' ,'msid' ,'st' ,'u_id' ,'db_flag'))
--LOOP
--colCount:=colCount+1;
--ssql1:='select '||columnlist.COLUMN_NAME||' from Main_Table where UID='||tblTABLE2_IDS(tblTABLE2_IDS.LAST)||'';
--dbms_output.put_line(ssql1);
--execute immediate ssql1 into testv;
--tblTABLE3_IDS(colCount):=testv;
--dbms_output.put_line(testv);
--END LOOP;
END IF;
END BEFORE EACH ROW;
--Executed aftereach row change- :NEW, :OLD are available
AFTER EACH ROW IS
BEGIN
IF UPDATING THEN
dbms_output.put_line('After Each Row - In Updating');
FOR columnlist IN
(SELECT COLUMN_NAME AS COLUMN_NAME FROM all_tab_columns WHERE lower(TABLE_NAME) = 'Main_Table'
AND lower(COLUMN_NAME) NOT IN ('s_id' ,'msid' ,'st' ,'u_id' ,'db_flag'))
LOOP
colCount:=colCount+1;
ssql1:='select '||columnlist.COLUMN_NAME||' from Main_Table where UID='||tblTABLE2_IDS(tblTABLE2_IDS.LAST)||'';
dbms_output.put_line(ssql1);
execute immediate ssql1 into testv;
tblTABLE3_IDS(colCount):=testv;
dbms_output.put_line(testv);
END LOOP;
END IF;
END AFTER EACH ROW;
--Executed after DML statement
AFTER STATEMENT IS
BEGIN
IF UPDATING THEN
dbms_output.put_line('After Statement - In Updating');
FOR columnlist IN
(SELECT COLUMN_NAME AS COLUMN_NAME FROM all_tab_columns WHERE lower(TABLE_NAME) = 'Main_Table'
AND lower(COLUMN_NAME) NOT IN ('s_id' ,'msid' ,'st' ,'u_id' ,'db_flag'))
LOOP
colCountAfter:=colCountAfter+1;
dbms_output.put_line('loop started');
ssql1:='select '||columnlist.COLUMN_NAME||' from Main_Table where UID='||tblTABLE2_IDS(tblTABLE2_IDS.LAST)||'';
execute immediate ssql1 into testv1;
dbms_output.put_line(testv);
tblTABLE3_IDS(colCountAfter):=testv1;
IF ((testv) IS NOT NULL) THEN
FOR i IN tblTABLE3_IDS.FIRST..tblTABLE2_IDS.LAST LOOP
dbms_output.put_line('Values No :' ||i||' is ' || tblTABLE3_IDS(i) || ' and ' ||tblTABLE4_IDS(i));
IF(tblTABLE3_IDS(i)=tblTABLE4_IDS(i)) THEN
dbms_output.put_line(testv1);
ELSE
-- dbms_output.put_line('select :new.'|| columnlist.COLUMN_NAME||' from dual');
dbms_output.put_line(testv1);
INSERT INTO Log_Table
(
user_id,
log_action,
log_table_name,
schema_name,
log_column_name,
col_old_val,
col_new_val,
ne_type,
ne_id,
system_id
)
VALUES
(
newuid,
'UPDATE',
'Main_Table',
'SCHEMA'
,columnlist.COLUMN_NAME
,tblTABLE3_IDS(i)
,tblTABLE4_IDS(i)
,'S'
,newstid
,newsid
);
END IF;
END LOOP;
END IF;
END LOOP;
END IF;
END AFTER STATEMENT;
END TRG_TEST;
는 처음에 내가 그때에 접근 시도 "각 행하기 전에"의 업데이트 테이블에 액세스 시도했다 두 경우 모두, 동일한 오류 "각 행 후".
복합 트리거를 사용한 후에도 해결책을 찾는데 어려움을 겪고 있지만 삽입을 위해 동일한 결과를 얻었습니다.
누구든지 어떻게 달성 할 수 있습니까? 미리 감사드립니다.
데이터베이스 버전 및 버전을 게시하십시오. 네가 바퀴벌레를 재가동한다고 생각해. 동일한 기능을 수행하는 오라클 제품이 몇 가지 있습니다. –
Oracle Database 12c Enterprise Edition 릴리스 12.1.0.1.0 - 64 비트 생산을 사용하고 있습니다. – nks
아니, 그냥. 런타임에 모든 단일 DML 문에 대해 동적 SQL *을 생성, 컴파일 및 실행한다는 아이디어는 정말 끔찍합니다. 트리거를 사용하여 모든 변경 사항을 추적해야하는 경우 각 테이블에 대한 트리거 코드를 개별적으로 생성하십시오. 당신은 많은 고통과 번거 로움을 덜어 주실 것입니다. –