[테스트 환경]
1.2. 시퀀스 생성 스크립트
1.3. 함수 생성 스크립트
1.4. 데이터 적재
1.5. 에러 발생 확인
2. 문제 원인 파악
2.3. 테이블 제약조건 제거
2.4. 데이터 적재
3. 결론
- Windows Server 2008 64bit
- Oracle 11g 64bit standard
1. 문제 상황
- 시퀀스를 사용해서 INSERT ALL로 부모 테이블과 자식 테이블에 데이터를 적재한다.
1.1. 테이블 생성 스크립트
-- 부모테이블 CREATE TABLE ADB_PARENTS ( PR_SEQNO NUMBER(9) NOT NULL, PARENTS_NM VARCHAR2(50) NULL ); ALTER TABLE ADB_PARENTS ADD CONSTRAINT PK_ADB_PARENTS1 PRIMARY KEY ( PR_SEQNO ); -- 자식테이블 CREATE TABLE ADB_CHILD ( PR_SEQNO NUMBER(9) NOT NULL, CHILD_NM VARCHAR2(50) NULL ); ALTER TABLE ADB_CHILD ADD CONSTRAINT PK_ADB_CHILD PRIMARY KEY ( PR_SEQNO ); ALTER TABLE ADB_CHILD ADD CONSTRAINT ADB_CHILD_FK FOREIGN KEY ( PR_SEQNO ) REFERENCES ADB_PARENTS ( PR_SEQNO );
CREATE SEQUENCE PR_SEQNO START WITH 1 MAXVALUE 999999999 MINVALUE 1 NOCYCLE NOCACHE NOORDER;
- 하나의 시퀀스 번호로 부모 테이블과 자식 테이블에 데이터를 적재해야하기 때문에 함수를 이용해서 채번한다.
CREATE OR REPLACE FUNCTION FN_ADB_SEQ(IN_VAL_CHK IN VARCHAR2) RETURN NUMBER AS V_SEQ NUMBER; BEGIN IF IN_VAL_CHK = 'PR_SEQNO' THEN SELECT PR_SEQNO.NEXTVAL INTO V_SEQ FROM DUAL; END IF; RETURN V_SEQ; END; /
INSERT ALL WHEN NO = 1 THEN INTO ADB_PARENTS(PR_SEQNO,PARENTS_NM) VALUES (PR_SEQNO, NM) WHEN NO = 2 THEN INTO ADB_CHILD(PR_SEQNO,CHILD_NM) VALUES (PR_SEQNO, NM) SELECT A.NO, A.PR_SEQNO, A.NM FROM (SELECT B.NO ,A.PR_SEQNO ,CASE WHEN B.NO = 1 THEN '부모테이블' || A.PR_SEQNO WHEN B.NO = 2 THEN '자식테이블' || A.PR_SEQNO END AS NM FROM (SELECT /*+ NO_MERGE */ FN_ADB_SEQ('PR_SEQNO') AS PR_SEQNO FROM DUAL CONNECT BY LEVEL <= 1000) A ,(SELECT ROWNUM AS NO FROM DUAL CONNECT BY LEVEL <= 2) B ORDER BY B.NO) A ORDER BY A.NO;
ORA-02291: 무결성 제약조건(ADB_CHILD_FK)이 위배되었습니다- 부모 키가 없습니다
- ORDER BY 정렬 순으로 데이터가 적재되지 않는 것을 확인
- 각 테이블에 적재된 시간을 알기 위해서 트리거를 사용한다.
2.1. 테이블 생성 스크립트
2.2. 트리거 생성 스크립트
CREATE TABLE ADB_PARENTS_CK(PR_SEQNO NUMBER, REG_DTTM TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL); CREATE TABLE ADB_CHILD_CK(PR_SEQNO NUMBER, REG_DTTM TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL);
- 부모 테이블과 자식 테이블에 데이터를 적재하기 전에 트리거로 2.1.에서 생성한 테이블에 적재 시간을 기록한다.
CREATE OR REPLACE TRIGGER TR_ADB_PARENTS BEFORE INSERT ON ADB_PARENTS REFERENCING NEW AS New OLD AS Old FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; V_PR_SEQNO NUMBER; BEGIN V_PR_SEQNO := :NEW.PR_SEQNO ; INSERT INTO ADB_PARENTS_CK (PR_SEQNO) VALUES (V_PR_SEQNO); COMMIT; END TR_ADB_PARENTS; / CREATE OR REPLACE TRIGGER TR_ADB_CHILD BEFORE INSERT ON ADB_CHILD REFERENCING NEW AS New OLD AS Old FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; V_PR_SEQNO NUMBER; BEGIN V_PR_SEQNO := :NEW.PR_SEQNO ; INSERT INTO ADB_CHILD_CK (PR_SEQNO) VALUES (V_PR_SEQNO); COMMIT; END TR_ADB_CHILD; /
ALTER TABLE ADB_CHILD DROP CONSTRAINT ADB_CHILD_FK;
INSERT ALL WHEN NO = 1 THEN INTO ADB_PARENTS(PR_SEQNO,PARENTS_NM) VALUES (PR_SEQNO, NM) WHEN NO = 2 THEN INTO ADB_CHILD(PR_SEQNO,CHILD_NM) VALUES (PR_SEQNO, NM) SELECT A.NO, A.PR_SEQNO, A.NM FROM (SELECT B.NO ,A.PR_SEQNO ,CASE WHEN B.NO = 1 THEN '부모테이블' || A.PR_SEQNO WHEN B.NO = 2 THEN '자식테이블' || A.PR_SEQNO END AS NM FROM (SELECT /*+ NO_MERGE */ FN_ADB_SEQ('PR_SEQNO') AS PR_SEQNO FROM DUAL CONNECT BY LEVEL <= 1000) A ,(SELECT ROWNUM AS NO FROM DUAL CONNECT BY LEVEL <= 2) B ORDER BY B.NO) A ORDER BY A.NO; COMMIT;
2.5. 결과
- ORDER BY 절의 순서대로 데이터가 적재되지 않고 자식 테이블에 데이터가 먼저 적재된 것을 확인할 수 있다.
SELECT A.PR_SEQNO, A.REG_DTTM AS PARENTS_REG_DTTM, B.REG_DTTM AS CHILD_REG_DTTM FROM ADB_PARENTS_CK A ,ADB_CHILD_CK B WHERE B.PR_SEQNO = A.PR_SEQNO;
- SELECT 절의 ORDER BY가 적재 순서를 보장하지 않는다.
따라서 INSERT ALL로 부모 테이블과 자식 테이블에
데이터를 적재할 때 FK 제약조건이 제거되어야 한다.
'Oracle > SQL' 카테고리의 다른 글
오라클 데이터 값에 엔터(ENTER) 값을 찾는 쿼리와 치환하는 방법 (0) | 2015.05.15 |
---|---|
V$SQLAREA (0) | 2015.04.20 |