본문 바로가기

SQL Server/SQL Server Tip & Tech

MERGE 응용 - 1. UPSERT

UPSERT ???

조건을 만족하는 행이 있으면 UPDATE하고, 그렇지 않으면 INSERT하는 구문입니다.
하지만, SQL Server에서는 UPSERT문을 지원하지 않습니다.


SQL Server 2008 - MERGE 문

SQL Server 2008에 추가된 MERGE 문을 사용하면 하나의 문에서 여러 INSERT, UPDATE 및 DELETE 작업을 수행할 수 있습니다.

단, MERGE문을 잘 못 작성하면 악성 쿼리로 전락하거나, 예기치 않은 동작으로 데이터의 손실을 유발할 수 있으니 익숙하게 사용할 수 있도록 테스트 구문을 많이 작성해 보시기 바랍니다.


MERGE 문으로 UPSERT를 구현

지금까지 SQL Server에서 UPSERT를 수행하려면, UPDATE 후 @@ROWCOUNT를 확인해 다시 INSERT 문을 실행하는 방식을 사용해야 했습니다.

하지만, 이 방식은 자칫 동시성 문제를 유발할 수 있기 때문에 잠금 힌트를 통한 세밀한 트랜잭션 제어를 필요로합니다.  숙련된 개발자에게는 별 문제가 아니겠지만, 안타깝게도 많은 개발자들이 이런 문제를 인식조차 하지 못합니다.

이에 비해 MERGE 문은 단일 문이라 동시성 문제를 크게 고려하지 않아도 될 뿐더러 대개 성능도 더 낫습니다.


Example

테스트 데이터 세팅

IF OBJECT_ID(N'TEST', N'U') IS NOT NULL

       DROP TABLE dbo.TEST;

GO

 

CREATE TABLE dbo.TEST (

       seq int IDENTITY(1, 1) NOT NULL,

       userSN int NOT NULL,

       col1 int NOT NULL

);

GO

 

INSERT dbo.TEST (userSN, col1)

VALUES (1, 10), (2, 20), (3, 30);

GO



seq

userSN

col1

1

1

10

2

2

20

3

3

30




MERGE 문을 사용하여 UPSERT

-- 1. userSN = 3인 행이 있으면 col1300으로 UPDATE하고, 없으면INSERT

 

MERGE dbo.TEST AS T

USING (SELECT 3, 300) AS S (userSN, col1)

ON T.userSN = S.userSN

WHEN MATCHED THEN

       UPDATE SET col1 = S.col1

WHEN NOT MATCHED BY TARGET THEN

       INSERT (userSN, col1) VALUES (S.userSN, S.col1);


Results :

 

seq

userSN

col1

1

1

10

2

2

20

3

3

300



-- 2. userSN = 4인 행이 있으면 col1 400으로 UPDATE하고, 없으면INSERT

 

MERGE dbo.TEST AS T

USING (SELECT 4, 400) AS S (userSN, col1)

ON T.userSN = S.userSN

WHEN MATCHED THEN

       UPDATE SET col1 = S.col1

WHEN NOT MATCHED BY TARGET THEN

       INSERT (userSN, col1) VALUES (S.userSN, S.col1);


Results :

seq

userSN

col1

1

1

10

2

2

20

3

3

300

4

4

400