본문 바로가기
프로그래밍/DBMS

오라클 MERGE INTO - 한번에 INSERT, UPDATE 하기

by zoo10 2011. 6. 3.

가끔 두 테이블을 비교해서 INSERT를 하거나 UPDATE 를 해야하는 경우가 발생한다. MSSQL 때는 IF EXISTS ... THEN 구문을 사용했었다. 사실 더 좋은 쿼리가 있었을지도 모르지만 내가 모르니까 모르는 것이겠지.

오라클로 인터페이스 작업을 하다보니 좀 파워있게 사용해야할 일이 많이 생겼다. 사실 인터페이스 작업이야 INSERT, UPDATE가 전부이니까. 오라클은 MSSQL같이 사용하지 못하길래 찾아봤더니 아주 멋진 녀석이 있었다. 단 제약조건은 좀 있지만서도.

일단은 오라클 9 버젼 이상부터 지원하는 것 같다.(아니면 강력하게 태클 요청 드림)
기본 구문은 아래에 있음.

MERGE INTO 타겟테이블 TT
    USING 
        소스테이블 ST
    ON (TT.필드1=ST.필드1 AND TT.필드2=ST.필드2 ....)
    
    WHEN MATCHED THEN -- 존재하면 UPDATE
        UPDATE SET
            TT.타겟_필드1=ST.소스_필드1
            ,TT.타겟_필드2=ST.소스_필드2

    WHEN NOT MATCHED THEN -- 없으면 INSERT
            INSERT (타겟_필드1, 타겟_필드2, 타겟_필드3....)
            VALUES(
                ST.소스_필드1
                , ST.소스_필드2
                , ST.소스_필드3
                .
				.
            );

이 녀석을 알기전에는 그냥 CURSOR로 처리했었는데 자료가 많이지지 속도가 너무 느렸다. MERGE INTO를 사용하니 아주 뛰어난 성능이 나타났다는. 사실 오라클을 아주 많이 아는게 아녀서 고수분들이 태클을 좀 걸어 주셨으면 좋겠다.

아래는 실제로 사용했던 예. 테이블 명은 임의로 바꿨다. 소스 테이블에 올 내용은 아래처럼 SELECT로 구성해도 된다.

merge into target_table tt
    using 
        (
            select 
                te.te_cd tt_cd
                ,te.description tt_disp
                ,te.jt_no jt_no
                ,decode(te.is_flag, 'normal', 'Y', 'N') is_flag
            from 
                temp_table te
            left join join_table jt
                on te.te_no=jt.jt_no
            where 
                1=1
        ) so
    on (tt.tt_cd=so.tt_cd and tt.jt_no=so.jt_no)
    
    when matched then
        update set
            tt.is_flag=so.is_flag
            ,tt.tt_disp=so.tt_disp


    when not matched then
            insert (tt_no, tt_cd, tt_disp, jt_no, is_flag, reg_date)
            values(
                sq_target_table.nextval
                , so.tt_cd
                , so.tt_disp
                , so.jt_no
                , so.is_flag
                , sysdate
            );