Dynamic Bulk Collect Forall Delete Auto generator (Table 단위 Bulk Collect Forall Delete 자동생성기)
업데이트:
Dynamic Bulk Collect Forall Delete Auto generator (Table 단위 Bulk Collect Forall Delete 자동생성기)
Auto Generator PL/SQL Block
원하는 Schema 의 테이블들을 대상으로 하여
Truncate 가 아닌 Delete 를 사용하여 처리 해야만 하는 제약이 있어
Bulk Collect Forall Delete 를 만들어 사용하게 되었고,
전체 Table에 대하여 자동생성해주는 PL/SQL 을 만들었다.
에러 테스트는 안해서, Exception 관련 부분은 정상 동작 보증 못함
DECLARE
L_SQL VARCHAR2(4000);
V_USER VARCHAR2(20) := 'TEST';
BEGIN
FOR C IN (SELECT * FROM ALL_TABLES WHERE OWNER = V_USER AND TABLE_NAME LIKE '%TB_M00%' AND TABLE_NAME NOT LIKE '%LOG%') LOOP
L_SQL := 'DECLARE '||
' CURSOR C1 IS '||
' SELECT * '||
' FROM '||C.TABLE_NAME||'; '||
' TYPE TABLE_TYPE IS TABLE OF C1%ROWTYPE INDEX BY PLS_INTEGER; '||
' REC_C1 TABLE_TYPE; '||
' V_LIMIT NUMBER := 1000; '||
'BEGIN '||
' OPEN C1; '||
' LOOP '||
' FETCH C1 BULK COLLECT INTO REC_C1 LIMIT V_LIMIT; '||
' FORALL I IN REC_C1.FIRST..REC_C1.LAST '||
' DELETE FROM '||C.TABLE_NAME||' WHERE ';
FOR D IN (SELECT * FROM ALL_CONS_COLUMNS WHERE OWNER = V_USER
AND CONSTRAINT_NAME = (SELECT CONSTRAINT_NAME FROM ALL_CONSTRAINTS WHERE OWNER = V_USER
AND TABLE_NAME = C.TABLE_NAME
AND CONSTRAINT_TYPE = 'P') ORDER BY POSITION) LOOP
L_SQL := L_SQL||D.COLUMN_NAME||' = REC_C1(I).'||D.COLUMN_NAME||' AND ';
END LOOP;
L_SQL := SUBSTR(L_SQL,1,LENGTH(L_SQL)-4)||';';
L_SQL := L_SQL||' EXIT WHEN REC_C1.COUNT < V_LIMIT; '||
' END LOOP; '||
' CLOSE C1; '||
' EXCEPTION '||
' WHEN OTHERS THEN '||
' DBMS_OUTPUT.put_line (SQLERRM); '||
' DBMS_OUTPUT.put_line (''DELETED ''||SQL%ROWCOUNT||'' ROWS.''); '||
' FOR INDX IN 1 .. SQL%BULK_EXCEPTIONS.COUNT LOOP '||
' DBMS_OUTPUT.PUT_LINE (''ERROR ''||INDX||'' OCCURRED ON INDEX ''||SQL%BULK_EXCEPTIONS (INDX).ERROR_INDEX||'' ATTEMPTING TO UPDATE NAME TO "''||SQL%BULK_EXCEPTIONS (INDX).ERROR_INDEX||''"''); '||
' DBMS_OUTPUT.PUT_LINE (''ORACLE ERROR IS ''||SQLERRM(-1 * SQL%BULK_EXCEPTIONS (INDX).ERROR_CODE)); '||
' END LOOP; '||
'END; ';
DBMS_OUTPUT.PUT_LINE(L_SQL);
--EXECUTE IMMEDIATE L_SQL;
END LOOP;
END;
/
Sample Bulk Collect Forall Delete
-- 자동생성기에는 맨 마지막 / slash 가 없습니다. 개별로 사용하게 되면 / 는 붙여줘야 합니다.
-- 이거 STRING 으로 하면 에러가 나서.. 일단 없앰..
-- EXECUTE 로 전체 돌리는데에는 문제는 없이 돌아갈테지만.. DBMS_OUTPUT 으로 뽑아서 사용시에는 / 를 각가 별도로 붙여줘야하는 단점이 있음..
DECLARE
CURSOR C1 IS
SELECT *
FROM TEST;
TYPE TABLE_TYPE IS TABLE OF C1%ROWTYPE INDEX BY PLS_INTEGER;
REC_C1 TABLE_TYPE;
V_LIMIT NUMBER := 1000;
BEGIN
OPEN C1;
LOOP
FETCH C1 BULK COLLECT INTO REC_C1 LIMIT V_LIMIT;
FORALL I IN REC_C1.FIRST..REC_C1.LAST
DELETE FROM TEST WHERE COL1 = REC_C1(I).COL1 AND COL2 = REC_C1(I).COL2;
EXIT WHEN REC_C1.COUNT < V_LIMIT;
END LOOP;
CLOSE C1;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line (SQLERRM);
DBMS_OUTPUT.put_line ('DELETED '||SQL%ROWCOUNT||' ROWS.');
FOR INDX IN 1 .. SQL%BULK_EXCEPTIONS.COUNT LOOP
DBMS_OUTPUT.PUT_LINE ('ERROR '||INDX||' OCCURRED ON INDEX '||SQL%BULK_EXCEPTIONS (INDX).ERROR_INDEX||' ATTEMPTING TO UPDATE NAME TO "'||SQL%BULK_EXCEPTIONS (INDX).ERROR_INDEX||'"');
DBMS_OUTPUT.PUT_LINE ('ORACLE ERROR IS '||SQLERRM(-1 * SQL%BULK_EXCEPTIONS (INDX).ERROR_CODE));
END LOOP;
END;
/