Oracle 두 동일한 테이블간의 Merge 문 자동 생성
업데이트:
Oracle 두 동일한 테이블간의 Merge 문 자동 생성
Oracle 두 동일한 테이블간의 Merge 문 자동 생성
#/bin/bash
TARGET_DB="TEST"
T_USER="TEST"
T_PWD="wony12"
####################
# AUTO GENERATE MERGE QUERY
####################
TAB_NM=$1
MERGE_DML=$(sqlplus -S $T_USER/$T_PWD@$TARGET_DB << EOF
SET FEEDBACK OFF
SET SERVEROUTPUT ON
DECLARE
CUR NUMBER;
RES NUMBER;
CNT INTEGER;
DESC_TAB DBMS_SQL.DESC_TAB;
V_VARCHAR VARCHAR2(32767);
V_DATE DATE;
V_TIMESTAMP TIMESTAMP;
V_NUMBER NUMBER;
COL_TYPE_NM VARCHAR2(300);
SKIP_YN VARCHAR2(20);
SQL_TEXT VARCHAR2(2000) := 'SELECT * FROM ${TAB_NM}';
WHERE_TEXT VARCHAR2(2000) := ' WHERE ROWNUM < 1';
OUTPUT VARCHAR2(32767) := 'MERGE INTO ${TAB_NM} A USING (SELECT * FROM ${TAB_NM}_MIG WHERE ';
BEGIN
DBMS_OUTPUT.ENABLE (BUFFER_SIZE => NULL);
CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(CUR, SQL_TEXT||WHERE_TEXT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS (CUR, CNT, DESC_TAB);
FOR C IN (SELECT * FROM ALL_CONS_COLUMNS WHERE OWNER = 'TEST' AND CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM ALL_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'P' AND OWNER = 'TEST' AND TABLE_NAME = '${TAB_NM}')) LOOP
OUTPUT := OUTPUT||C.COLUMN_NAME||' = CUR_ROW(C).'||C.COLUMN_NAME||' AND ';
END LOOP;
OUTPUT := SUBSTR(OUTPUT, 1, LENGTH(OUTPUT) - 4);
OUTPUT := OUTPUT||') B ';
OUTPUT := OUTPUT||'ON (';
FOR C IN (SELECT * FROM ALL_CONS_COLUMNS WHERE OWNER = 'TEST' AND CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM ALL_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'P' AND OWNER = 'TEST' AND TABLE_NAME = '${TAB_NM}')) LOOP
OUTPUT := OUTPUT||'A.'||C.COLUMN_NAME||' = B.'||C.COLUMN_NAME||' AND ';
END LOOP;
OUTPUT := SUBSTR(OUTPUT, 1, LENGTH(OUTPUT) - 4);
OUTPUT := OUTPUT||') ';
OUTPUT := OUTPUT||'WHEN MATCHED THEN UPDATE SET ';
FOR I IN 1 .. CNT LOOP
SKIP_YN := 'FALSE';
FOR C IN (SELECT * FROM ALL_CONS_COLUMNS WHERE OWNER = 'TEST' AND CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM ALL_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'P' AND OWNER = 'TEST' AND TABLE_NAME = 'TB_M00_ATTRS')) LOOP
IF ( C.COLUMN_NAME = DESC_TAB(I).COL_NAME ) THEN
SKIP_YN := 'TRUE';
END IF;
END LOOP;
IF ( SKIP_YN = 'FALSE' ) THEN
OUTPUT := OUTPUT||DESC_TAB(I).COL_NAME||'=CUR_ROW(C).'||DESC_TAB(I).COL_NAME||',';
END IF;
END LOOP;
OUTPUT := SUBSTR(OUTPUT, 1, LENGTH(OUTPUT) - 1);
OUTPUT := OUTPUT||' WHEN NOT MATCHED THEN INSERT VALUES CUR_ROW(C)';
DBMS_OUTPUT.PUT_LINE(OUTPUT);
END;
/
EOF
)
echo "${MERGE_DML}"
RES=$(sqlplus -S $T_USER/$T_PWD@$TARGET_DB << EOF
SET FEEDBACK OFF
SET SERVEROUTPUT ON
DECLARE
ERRORS NUMBER;
CURSOR CUR_TAB IS SELECT * FROM ${TAB_NM}_MIG;
TYPE CUR_TYPE IS TABLE OF ${TAB_NM}%ROWTYPE ;
CUR_ROW CUR_TYPE;
BEGIN
DBMS_OUTPUT.ENABLE (BUFFER_SIZE => NULL);
OPEN CUR_TAB;
LOOP
FETCH CUR_TAB BULK COLLECT INTO CUR_ROW;
FORALL C IN CUR_ROW.FIRST .. CUR_ROW.LAST SAVE EXCEPTIONS
"${MERGE_DML}"
EXIT WHEN CUR_ROW.COUNT = 0;
END LOOP;
CLOSE CUR_TAB;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
WHEN DML_ERRORS THEN
ERRORS := SQL%BULK_EXCEPTIONS.COUNT;
DBMS_OUTPUT.PUT_LINE ('THE TOTAL NUMBER OF ERRORS OCCURED ARE '|| ERRORS);
FOR J IN 1..ERRORS LOOP
DBMS_OUTPUT.PUT_LINE ('THE ERROR ITERATION IS '
|| SQL%BULK_EXCEPTIONS(J).ERROR_INDEX
|| ' AND THE ERROR CODE IS '
|| SQL%BULK_EXCEPTIONS(J).ERROR_CODE
|| ' AND THE ERROR MESSAGE IS '
|| SQLERRM (- SQL%BULK_EXCEPTIONS(J).ERROR_CODE)
);
END LOOP;
COMMIT;
END;
/
EOF
)
echo "$RES"