1 | 목표: |
PRIMARY KEY = GPI001 + GPI002
임시 테이블(S라 칭함)의 GPI001,GPI002 컬럼이
원본 테이블(T라 칭함)의 GPI001,GPI002 컬럼값과 서로 일치하고,
S와 T의 GPI003,GPI004,GPI005의 값이 서로 다를 경우
T의 GPI003,GPI004,GPI005 값을 S의 GPI003,GPI004,GPI005 의 값으로 UPDATE한다.
T의 GPI006 값은 컬럼값이 업데이트 되었을경우 기존값과 업데이트 후 의 값을 나타내준다.
-------------UPDATE 종료--------------
임시테이블의 GPI001,GPI002 값이 원본테이블의 GPI001,GPI002 에 존재하지 않을경우
원본테이블에 임시테이블의 GPI001 ~ GPI007 까지의 값을 INSERT 한다.
-------------INSERT 종료 ---------------
원본테이블의 GPI001,GPI002 값이 임시테이블 GPI001,GPI002에 존재하지않을경우
원본테이블 GPI007 값을 '단종' 으로 UPDATE 한다.
작성쿼리:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | MERGE Into tableName AS T USING Temp_tableName AS S ON T.GPI001 = S.GPI001 AND T.GPI002 = S.GPI002 AND (T.GPI003 <> S.GPI003 OR T.GPI004 <> S.GPI004 OR T.GPI005 <> S.GPI005) WHEN MATCHED THEN UPDATE SET T.GPI003 = S.GPI003 , T.GPI004 = S.GPI004 , T.GPI005 = S.GPI005 , T.GPI006 = ( CASE WHEN T.GPI003 <> S.GPI003 THEN '[상품명]' + T.GPI003 + '→' + S.GPI003 + ' ; ' ELSE '' END + CASE WHEN T.GPI004 <> S.GPI004 THEN '[구매가]' + T.GPI004 + '→' + S.GPI004 + ' ; ' ELSE '' END + CASE WHEN T.GPI05 <> S.GPI05THEN '[품절여부]' + T.GPI05 + '→' + S.GPI05 + ' ; ' ELSE '' END ); INSERT INTO tableName(GPI001,GPI002,GPI003,GPI004,GPI005,GPI006,GPI007) SELECT S.GPI001,S.GPI002,S.GPI003,S.GPI004,S.GPI005,S.GPI006, '신규' FROM Temp_tableName S WHERE NOT EXISTS ( SELECT 'X' FROM tableName WHERE GPI001 = S.GPI001 AND GPI002 = S.GPI002); UPDATE T SET T.GPI007 = '단종' FROM tableName T WHERE NOT EXISTS ( SELECT 'X' FROM Temp_tableName WHERE GPI001 = T.GPI001 AND GPI002 = T.GPI002); |
C# 반복문 내에서 한 레코드씩 DB에 쿼리를 수행하다보니 너무 느려서 위처럼 한번에 MERGE문을 사용하려고 하는데요,
개선할 부분이 있을지 조언주신다면 감사하겠습니다
그리고 위처럼 작성을 하면 MERGE문의 범위가 맨밑의 단종처리를 해주는 쿼리까지 포함되는게 맞을까요?
MERGE 문을 UPDATE 용으로만 사용하고, INSERT 문을 별개로 수행하고 있고,
추가 UPDATE 구문까지 총 3개 구문이 실행되네요.
MERGE 구문 하나로 가능합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | MERGE INTO tableName t USING Temp_tableName s ON t.gpi001 = s.gpi001 AND t.gpi002 = s.gpi002 WHEN MATCHED AND t.gpi003 != s.gpi003 AND t.gpi004 != s.gpi004 AND t.gpi005 != s.gpi005 THEN UPDATE SET gpi003 = s.gpi003 , gpi004 = s.gpi004 , gpi005 = s.gpi005 , gpi006 = CASE WHEN t.gpi003 <> s.gpi003 THEN '[상품명]' + t.gpi003 + '→' + s.gpi003 + ' ; ' ELSE '' END + CASE WHEN t.gpi004 <> s.gpi004 THEN '[구매가]' + t.gpi004 + '→' + s.gpi004 + ' ; ' ELSE '' END + CASE WHEN t.gpi005 <> s.gpi005 THEN '[품절여부]' + t.gpi005 + '→' + s.gpi005 + ' ; ' ELSE '' END , gpi007 = '변경' WHEN NOT MATCHED THEN INSERT (gpi001, gpi002, gpi003, gpi004, gpi005, gpi006, gpi007) VALUES (s.gpi001, s.gpi002, s.gpi003, s.gpi004, s.gpi005, '' , '신규' ) WHEN NOT MATCHED BY SOURCE THEN UPDATE SET gpi007 = '단종' ; |
1 2 3 4 5 6 7 8 | MERGE INTO tableName t USING Temp_tableName s ON t.gpi001 = s.gpi001 AND t.gpi002 = s.gpi002 WHEN MATCHED AND (t.gpi003 != s.gpi003 OR t.gpi004 != s.gpi004 OR t.gpi005 != s.gpi005) THEN UPDATE ... |
개선해 주신 위 코드와
1 2 3 4 5 6 7 8 | MERGE INTO tableName t USING Temp_tableName s ON t.gpi001 = s.gpi001 AND t.gpi002 = s.gpi002 AND (t.gpi003 != s.gpi003 OR t.gpi004 != s.gpi004 OR t.gpi005 != s.gpi005) WHEN MATCHED THEN ... |
제가 작성한 기존 코드랑 비교했을떄
1 2 3 | AND (t.gpi003 != s.gpi003 OR t.gpi004 != s.gpi004 OR t.gpi005 != s.gpi005) |
이부분을 WHEN MATCHED 위에 넣느냐(제가 작성한)
WHEN MATCHED 뒤에 AND로 연결하느냐(마농님께서 작성하신) 의
차이가 있을까요?
그리고 맨 밑 라인에서 SOURCE 와 매치되지않을때 수행하는
UPDATE SET GPI007 ='단종' 을 아래처럼 수정하려고하는데요,
UPDATE SET GPI007 ='단종' , T.GPI008 = T.GPI007 + '→' + S.GPI0007;
이렇게 GPI008 컬럼값을
기존에 gpi007 값이 판매 였을경우 판매 → 단종 이런식으로 UPDATE 해주려고 하는데
수행시 [여러 부분으로 구성된 식별자 "S.GPI007"은(는) 바인딩할 수 없습니다.]
라는 에러가 발생되는데 검색해보니 테이블 별칭을 지정해주지 않을경우에 발생되는 에러라고 하더라구요
그런데 위에서 별칭을 S로 지정해주었는데도 왜 뜨는지 원인을 잘모르겠네요..ㅠ
혹시 조언을 주신다면 정말 감사하겠습니다
답변주신 내용중에 조인조건,필터조건의 차이가
아래 제가 이해한 내용이 맞을까요??
1. 조인조건 (003~005가 WHEN 앞에 옴)
001~002만 일치하면 UPDATE 문을 수행하고 WHEN NOT MATCHED는 001~002가 다르면 수행
위에서 001~002가 다르면 UPDATE문이 수행되지만 해당 UPDATE문 안에서도 003~005가 달라야 아래 THEN UPDATE 구문이 수행됨
따라서 만약 003~005가 다르지 않으면 UPDATE문이 수행되더라도 실질적으로 변경되는 내용은 없음
2. 필터조건 (003~005가 WHEN 뒤에 옴)
001~005가 모두 같아야 UPDATE 문을 수행하고
아래 WHEN NOT MATCHED는 001~005가 모두 달라야 수행됨