반응형

레코드가 있으면 UPDATE하고 없으면 INSERT해라 였는데,
오라클9i에서 새로 추가된 MERGE INTO 구문을 사용하면

대략 구문은 아래와 같습니다.
pl/sql환경에서는 위와 같이 사용해도 되지만,
sql을 꼭 사용해야한다면 이 방법이 낫겠네요.

[SYNTAX]

MERGE INTO 테이블 A                        -- update 또는 insert할 테이블
USING (테이블명 | SUBQUERY | 뷰)  B  -- 비교 대상
ON(A와 B의 조인식)                             -- 대상테이블과 비교테이블의 조인식
WHEN MATCHED THEN                       -- on절에서 일치하는 로우가 있다면
    UPDATE SET = , , ....                       -- 업데이트하고,
WHEN NOT MATCHED THEN                -- 일치하는 로우가 없다면
    INSERT INTO(컬럼명)                       -- insert를
    VALUES(값, 값, ...)                           -- 이 값으로 넣어라.

f_u1:
   merge into tb_result a
        using dual             b
           on ( a.plt_no = '$in_plt_no' and
                a.srt_id = '$in_srt_id' )
   when matched then
      update set srt_qty     = srt_qty + to_number('$in_srt_qty'),
                 fin_chgr_id = '$in_user_id',
                 fin_chg_dtm = to_char(sysdate, 'yyyymmddhh24miss')
   when not matched then
      insert ( plt_no       , srt_id            , proj_no         , blk_no            ,
               sass_no      , prcd_sass_no      , ptlst_no        , pcs_gb            ,
               stype        , srt_qty           , uom_wgt         , bom_org_cmpo      ,
               io_gb        , req_gb            , ptlst_stat      , req_ser           ,
               lug_gb       , mpart_plt_no      , newprod_qty     , reprod_qty        ,
               imprv_yn     , plt_incd_yn       , fs_srt_usr_id   , fs_srt_dtm        ,
               fs_inpr_id )
      values ( '$in_plt_no' , '$in_srt_id'      , '$in_proj_no'   , '$in_blk_no'      ,
               '$in_sass_no', '$in_prcd_sass_no', '$in_ptlst_no'  , '$in_pcs_gb'      ,
               '$in_stype'  , to_number('$in_srt_qty'), to_number('$in_uom_wgt'), '$in_bom_org_cmpo',
               '$in_io_gb'  , '$in_req_gb'      , 'C'             , to_number('$in_req_ser'),
               '$in_lug_gb' , '$in_mpart_plt_no', to_number('$in_new_srt_qty'), to_number('$in_re_srt_qty'),
               'N'          , 'Y'               , '$in_user_id'   , to_char(sysdate, 'yyyymmddhh24miss'),
               '$in_user_id' )
   ;

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

f_u2:
   declare cursor csr1 is
      select a.lug_gb       as lug_gb  ,
             a.ptlst_no     as lug_type,
             '$in_bizcls'   as bizcls  ,
             sum(a.srt_qty) as srt_qty
      from   tb_result a
      where  a.plt_no = '$in_plt_no'
      group  by a.lug_gb, a.ptlst_no
      $in_semicolon

      begin
         for rec1 in csr1 loop
            update tb_result
            set    stk_qty     = stk_qty - rec1.srt_qty * decode('$in_out_gb', 'O', 1, -1),
                   fin_chgr_id = '$in_user_id',
                   fin_chg_dtm = to_char(sysdate, 'yyyymmddhh24miss')
            where  lug_gb      = rec1.lug_gb
            and    lug_type    = rec1.lug_type
            and    bizcls      = rec1.bizcls
            $in_semicolon

            if sql%notfound then
               insert into tb_stk
                         ( lug_gb    ,
                           lug_type  ,
                           bizcls    ,
                           stk_qty   ,
                           fs_inpr_id    )
                  values ( rec1.lug_gb  ,
                           rec1.lug_type,
                           rec1.bizcls  ,
                           rec1.srt_qty * decode('$in_out_gb', 'O', -1, 1),
                           '$in_user_id' )
               $in_semicolon
            end if $in_semicolon
         end loop $in_semicolon
      end $in_semicolon
   ;

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

테이터를 넣어야할 테이블에

값이 이미 있으면 Update

값이 없으면 Insert

 

MERGE INTO table_name alias                               --테이블 명만 올수 있음(셀렉트 쿼리 No)
          USING (table|view|subquery) alias                --일반적으로 쓰는 쿼리 Ok
          ON (join condition)                                        --where 절이라고 생각하면됨(조건에 서브 OK)
          WHEN MATCHED THEN                              --데이터 중복건이 있는경우 Update
                       UPDATE SET col1 = val1[, col2 = val2…]
          WHEN NOT MATCHED THEN                      -- 중복건이 없는 경우 처리 Insert
                       INSERT (컬럼리스트) VALUES (값들....);

ex)

   MERGE INTO CRCD_WF_CARD A            
   USING DUAL                           
      ON ( A.WF_NO = ? AND A.CRD_NO =? )
    WHEN MATCHED    THEN                
         UPDATE  SET                    
                 A.CRD_TYPE       =?    
               , A.FML_SSN        =?    
               , A.FMLHG_NM       =?    
               , A.FMLENG_NM      =?    
               , A.OCRD_NO        =?    
               , A.DSN_CD         =?    
               , A.DSN_NM         =?    
               , A.BRD_CD         =?    
               , A.CRD_GRD        =?    
               , A.INTGLMT_AMT    =?    
               , A.FML_STLACCT_NO =?    
               , A.CRD_ISSUE_DT   =?    
    WHEN NOT MATCHED THEN               
         INSERT (                       
                 A.WF_NO                
               , A.CRD_NO               
               , A.CRD_TYPE             
               , A.FML_SSN              
               , A.FMLHG_NM             
               , A.FMLENG_NM            
               , A.OCRD_NO              
               , A.DSN_CD               
               , A.DSN_NM               
               , A.BRD_CD               
               , A.CRD_GRD              
               , A.INTGLMT_AMT          
               , A.FML_STLACCT_NO       
               , A.CRD_ISSUE_DT         
                                        
       ) VALUES ( ?, ?, ?, ?, ?, ?, ?,  
                  ?, ?, ?, ?, ?, ?, ?  )

-------------------------------------------------------

ex2)

    MERGE INTO TC_CUSTAGENT A
   USING (SELECT BUSI_CODE, CUST_CODE, CHPE_NAME, CUST_PHNB, CUST_FANU
                FROM TB_ESTMAST
                WHERE BUSI_CODE = '___parameter___'

                     AND CUST_CODE = '____parameter___') B
    ON (A.BUSI_CODE = B.BUSI_CODE
           AND A.AFON_COMP = B.CUST_CODE
           AND A.SEQU_NUMB = (SELECT MAX(SEQU_NUMB)
                                            FROM TC_CUSTAGENT
                                            WHERE BUSI_CODE = A.BUSI_CODE
                                                  AND AFON_COMP = A.AFON_COMP))
   WHEN MATCHED THEN
         UPDATE
         SET  A.CHPE_NAME = B.CHPE_NAME
                ,A.CABL_PHNB = B.CUST_PHNB
                ,A.FAXM_NUMB = B.CUST_FANU
    WHEN NOT MATCHED THEN
         INSERT (  A.AFON_COMP
                       ,A.CHPE_NAME
                       ,A.CABL_PHNB
                       ,A.FAXM_NUMB     
                     )
         VALUES (  B.CUST_CODE
                        ,B.CHPE_NAME      
                        ,B.CUST_PHNB
                        ,B.CUST_FANU    
                      );


>>>>>>>>>>>>>>>>
 
 MERGE INTO
실제 적용하면서 발견한 문제점 (ORACLE 9.2.0.3.0 에서)

 

9.2.0.4.0 버젼에선 아래와 같은 문법으로도 MERGE INTO 가 정상적으로 동작하였다.

 

MERGE INTO POPULAR_KEYWORD
USING DUAL B
ON (FIX_YN = 'Y' AND CATEGORY = 'ALL' AND RANK = '1')
WHEN MATCHED THEN
  UPDATE SET REG_DATE = SYSDATE
WHEN NOT MATCHED THEN
  INSERT (CATEGORY,KEYWORD,RANK, COUNT, REG_DATE)
      VALUES ('ALL','TEST22','1','100',SYSDATE)

 

즉, ON 절에서 값이 NULL 이더라도 WHEN NOT MATCHED THEN 절을 정상적으로 수행하였는데

 

이상하게 다른서버(9.2.0.3.0) 에선 ON절의 값이 NULL 이면 정상적인 루틴을 밟지 못하드라..

즉, INSERT 문을 수행하지 못했다.

[ 0 rows Merged ]

 

그래서 아래와 같이 USING절에서 NULL값이 리턴하지 않게 변경해주고

ON 절에서 A 와 B 를 JOIN 해주니까 정상적으로 동작한다.

 

MERGE INTO POPULAR_KEYWORD2 A
      USING (SELECT 'ALL' CATEGORY, '4' RANK, 'Y' FIX_YN FROM   DUAL) B
      ON (A.CATEGORY = B.CATEGORY AND A.RANK = B.RANK AND A.FIX_YN = B.FIX_YN)
      WHEN MATCHED THEN
        UPDATE SET REG_DATE = SYSDATE
      WHEN NOT MATCHED THEN
        INSERT (CATEGORY,KEYWORD,RANK, COUNT, REG_DATE)
            VALUES ('ALL','TEST22','4','100',SYSDATE)

[ 1 rows Merged ]

 

결론 ==> USING 다음의 SELECT 문의 결과 데이타는 반드시 존재하여야 한다 (NULL 불가).

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

9i이상에서는 데이타가 존재할 경우 갱신 없으면 등록하는 명령어로

MERGE INTO ~ USING ~ ON ~ WHEN ~ 명령어가 있습니다.


 

MERGE INTO oc_whslr_trd_rslt A
USING (
SELECT std_yymm, cust_nbr, whlsr_cust_nbr, sol_tp_cd, sol_cd,chnn_rt,

src_tp_cd,org_cd, emp_nbr,sell_amt, qty
FROM oc_temp_whslr_trd_rslt
) B
ON (

A.std_yymm = B.std_yymm AND

A.cust_nbr = B.cust_nbr AND

A.whlsr_cust_nbr = B.whlsr_cust_nbr AND

A.sol_cd = B.sol_cd AND

A.sol_tp_cd = B.sol_tp_cd AND

A.chnn_rt = B.chnn_rt
)
WHEN MATCHED THEN

UPDATE SET A.sell_amt = A.sell_amt + B.sell_amt,
A.qty = A.qty + B.qty
WHEN NOT MATCHED THEN
INSERT (
A.std_yymm,
A.cust_nbr,
A.whlsr_cust_nbr,
A.sol_cd,
A.sol_tp_cd,
A.chnn_rt,
A.src_tp_cd,
A.org_cd,
A.emp_nbr,
A.sell_amt,
A.qty,
A.drtn_amt,
A.drtn_qty,
A.last_chng_emp,
A.last_chng_dt )
VALUES (
B.std_yymm,
B.cust_nbr,
B.whlsr_cust_nbr,
B.sol_cd,
B.sol_tp_cd,
B.chnn_rt,
B.src_tp_cd,
B.org_cd,
B.emp_nbr,
B.sell_amt,
B.qty,
0,
0,
'CRMSP',
TO_CHAR(sysdate,'YYYYMMDD')
);

 

 

 

MERGE into KAC_PERSON a USING
(select user_id, OPER_FG, VARDATA, NUMDATA from KAC_PERSON
where user_id='57CCF7ADE63F3AC1' AND OPER_FG = 'MAIL_CAPACITY') b
ON (a.user_id=b.user_id and a.OPER_FG=b.OPER_FG)
WHEN MATCHED THEN UPDATE set a.NUMDATA = 15
WHEN NOT MATCHED THEN INSERT (a.user_id,a.OPER_FG,a.VARDATA,a.NUMDATA)
VALUES ('57CCF7ADE63F3AC1','MAIL_CAPACITY','mail',50)

 

CREATE TABLE KAC_PERSON
(
  USER_ID    CHAR(16) NOT NULL,
  OPER_FG    VARCHAR2(20) NOT NULL,
  VARDATA    VARCHAR2(30),
  NUMDATA    NUMBER(4),
  CONSTRAINT PK_KAC_PERSON PRIMARY KEY (USER_ID, OPER_FG)
);

>>>>>>>>>>>>>>>>>>>>>>>>>


MERGE INTO tb_target a
USING (
   select proj_no, spl_no, tag_no, msch_actv, instl_plt_no, wk_ord_dt
   from   tb_source
   where  lot_no  = 'AJ'
   and    proj_no = '1697'
   ) b
ON (   a.proj_no = b.proj_no
   and a.spl_no  = b.spl_no
   and a.tag_no  = b.tag_no)
WHEN MATCHED THEN
   update
   set    a.mk_fndt   = b.wk_ord_dt,
          a.matdlv_dt = b.wk_ord_dt,
          a.gr_dt     = b.wk_ord_dt,
          a.stk_dt    = b.wk_ord_dt,
          a.gi_dt     = b.wk_ord_dt
WHEN NOT MATCHED THEN
   insert(a.proj_no, a.spl_no, a.tag_no, a.msch_actv, a.instl_plt_no,
          a.mk_fndt, a.matdlv_dt, a.gr_dt, a.stk_dt, a.gi_dt)
   values(b.proj_no, b.spl_no, b.tag_no, b.msch_actv, b.instl_plt_no,
          b.wk_ord_dt,b.wk_ord_dt,b.wk_ord_dt,b.wk_ord_dt,b.wk_ord_dt)

반응형

+ Recent posts