아래와 같은 테이블에 대하여 USERID 가 존재할 경우에는 UPD_DATE 를 현재 날짜로 갱신하고

존재하지 않을 경우에는 INSERT 하는 쿼리를 Merge Into로 만들경우 아래와 같이 작성하게 되면

UPDATE 는 되는데 INSERT 는 되지 않습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SET SERVEROUTPUT ON;
 
BEGIN 
 
MERGE INTO TBL_USER TA
USING (SELECT USERIDX, USERID, USERNAME FROM TBL_USER WHERE USERID='6') TB
ON (TA.USERIDX = TB.USERIDX)
WHEN MATCHED THEN
    UPDATE SET TA.UPD_DATE = SYSDATE
WHEN NOT MATCHED THEN
    INSERT (TA.USERIDX, TA.USERID, TA.USERNAME)
    VALUES (6'6''NM_6')
;
dbms_output.put_line(SQL%ROWCOUNT);
COMMIT;
 
END;
 

아래와 같이 변경하시면

데이터가 있을 경우 Update, 없을 경우 Insert를 수행하게 됩니다.

- 중요한 부분은 위 TB 집합을 DUAL 로 변경하고 ON 절에 Where 조건을 기입하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SET SERVEROUTPUT ON;
 
BEGIN 
 
MERGE INTO TBL_USER TA
USING DUAL
ON (TA.USERID = '6')
WHEN MATCHED THEN
    UPDATE SET TA.UPD_DATE = SYSDATE
WHEN NOT MATCHED THEN
    INSERT (TA.USERIDX, TA.USERID, TA.USERNAME)
    VALUES (6'6''NM_6')
;
dbms_output.put_line(SQL%ROWCOUNT);
COMMIT;
 
END;
 

 

실행 결과 입니다.

Merge Into 실행 결과

오라클

아래와 같이 구분자로 구분된 여러 항목이 들어 있는 문자열을 파싱하여 표 형태로 출력해 주는 쿼리 입니다.

EX) '1/1/W/101_1/2/H/201_1/3/H/301_2/3/H/501_3/4/H/601_4/5/H/701'

Row 구분자 :  "_"

Column 구분자 : "/"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  SELECT TD.RNUM
  , MAX(CASE WHEN TD.LV = 1 THEN TD.TXT ELSE NULL END) COL1
  , MAX(CASE WHEN TD.LV = 2 THEN TD.TXT ELSE NULL END) COL2
  , MAX(CASE WHEN TD.LV = 3 THEN TD.TXT ELSE NULL END) COL3
  , MAX(CASE WHEN TD.LV = 4 THEN TD.TXT ELSE NULL END) COL4
  FROM (
  SELECT TB.RNUM, TC.LV ,regexp_substr(TB.TXT, '[^/]+'1, TC.LV) TXT
  FROM (
  SELECT rownum RNUM,regexp_substr(TA.TXT, '[^_]+'1, LEVEL) TXT
  FROM (SELECT '1/1/W/101_1/2/H/201_1/3/H/301_2/3/H/501_3/4/H/601_4/5/H/701' TXT FROM dual) TA
  CONNECT BY LEVEL <= length(regexp_replace(TA.TXT, '[^_]+',''))+1
  ) TB, (SELECT LEVEL LV FROM DUAL CONNECT BY LEVEL <= 4) TC ) TD
  GROUP BY TD.RNUM
  ORDER BY TD.RNUM ASC;
cs

▶ 출력 결과


기타 문의 사항은 덧글로 부탁 드립니다.


문자열로 아이템 목록을 전달하여 테이블에 저정해야 하는 상황이 종종 있습니다.

,(콤마) 나 |(파이프문자)로 구분된 문자열을 던져  While 안에서 instr + left 의 조합으로 파싱하여 

테이블에 insert 하는 방법이 있지만 구닥다리 에 성능도 좋지 않다.


mssql 이나 oracle 에서는 xml 문자열을 파싱할 수 있는 함수가 있는데 이를 이용하면 손쉽게 테이블에 insert 할 수 있다.

* xml을 사용하면 태그 문자가 붙어 문자열이 길어져 성능상 안좋다고 하는 사람들이 있을 수 있는데. 그런 사람들은 꼭~ 피해 다니길 당부 드린다.


먼저 아이템 목록이 담긴 xml 문자열 입니다.

"<items>  

<item><id>M4A1</id><price>500</price></item>

<item><id>AK47</id><price>600</price></item>

<item><id>9A-91</id><price>700</price></item>

<item><id>M4</id><price>700</price></item>  

</items>"


Oracle SP 입니다.

  PROCEDURE SP_XML_SAVE

  (

    i_xml VARCHAR2 

  )

  IS

  BEGIN

         

    INSERT INTO T_ITEMS(ID,PRICE)

    SELECT 

        EXTRACTVALUE ( column_value, '/item/id' ) id                                                       --item 하위 id 속성의 값을 가져옴 

        ,to_number(EXTRACTVALUE ( column_value, '/item/price' )) price                         --값 추출 후 숫자형으로 변환

    FROM TABLE ( XMLSEQUENCE ( EXTRACT ( xmltype ( i_xml ), '/items/item' ) ) ) p;  --items 하위 item 목록 집합을 추출  

    

  END SP_XML_SAVE; 


SP 테스트 입니다.

DECLARE

  I_XML VARCHAR2(2000);

BEGIN

  I_XML := '<items> <item><id>M4A1</id><price>500</price></item>

                    <item><id>AK47</id><price>600</price></item>

                    <item><id>9A-91</id><price>700</price></item> </items>';


  PKG_SUB.SP_XML_SAVE(I_XML => I_XML);

END;


결과:



xml 문자열로 입력받은 아이템 목록이 테이블에 잘 저장되어 있습니다.

위 내용은 ORACLE SQL Developer 에서 작성 및 테스트 되었습니다.


기타 궁금한 사항, 논의해 보고 싶으신 사항은 댓글 남겨 주세요. 언제나 환영 합니다.


+ Recent posts