SQL Server 2005의 MySQL REPLACE INTO 구현?


86

MySQL에는 매우 유용하면서도 독점적 인 REPLACE INTOSQL 명령이 있습니다.

SQL Server 2005에서이를 쉽게 에뮬레이션 할 수 있습니까?

새 트랜잭션을 시작하고 a를 수행 한 Select()다음 UPDATE또는 INSERTCOMMIT 수행하는 것은 특히 응용 프로그램에서 수행하고 따라서 항상 두 가지 버전의 문을 유지할 때 약간의 고통입니다.

SQL Server 2005에 이러한 기능을 구현 하는 쉽고 보편적 인 방법 이 있는지 궁금합니다 .

답변:


60

이것은 MSSQL에 대해 나를 괴롭히는 것입니다 ( 내 블로그에서 폭언 ). MSSQL이 지원되기를 바랍니다.upsert .

@ Dillie-O의 코드는 이전 SQL 버전 (+1 투표)에서 좋은 방법이지만 여전히 기본적으로 두 개의 IO 작업 ( exists다음 update또는insert )입니다.

이 게시물 에는 기본적으로 약간 더 나은 방법 이 있습니다 .

--try an update
update tablename 
set field1 = 'new value',
    field2 = 'different value',
    ...
where idfield = 7

--insert if failed
if @@rowcount = 0 and @@error = 0
    insert into tablename 
           ( idfield, field1, field2, ... )
    values ( 7, 'value one', 'another value', ... )

이렇게하면 업데이트 인 경우 하나의 IO 작업으로, 삽입 인 경우 두 번으로 줄어 듭니다.

MS Sql2008 merge은 SQL : 2003 표준을 도입 했습니다.

merge tablename as target
using (values ('new value', 'different value'))
    as source (field1, field2)
    on target.idfield = 7
when matched then
    update
    set field1 = source.field1,
        field2 = source.field2,
        ...
when not matched then
    insert ( idfield, field1, field2, ... )
    values ( 7,  source.field1, source.field2, ... )

이제는 실제로 하나의 IO 작업이지만 끔찍한 코드입니다 :-(


감사합니다! Select를 저장하고 Update와 "my"삽입 사이에 해당 키에 대한 다른 삽입이 없음을 확인할 수있는 상황에서 종종 teransaction이 필요하지 않습니다.
Michael Stum

2
@Michael이 솔루션을 사용하려는 경우이 테이블에 대한 고유 인덱스와 중복 키 오류 처리가 더 좋습니다.
Sam Saffron

3
@Keith 병합 문이 작동하지 않습니다. 절을 MERGE지원하지 않는 경우 및 WHERE을 사용하여 다시 작성해야 합니다. 또한를 추가하지 않으면 경주 가 발생 하고 동시 발생이 발생할 수 있으며 그중 하나가 키 충돌로 인해 실패 할 수 있습니다. USINGONWITH (HOLDLOCK)INSERT
Evgeniy Berezovsky

예, 여기에서 지적했듯이 : weblogs.sqlteam.com/dang/archive/2009/01/31/… MERGE는 원 자성이 아닙니다. 암시 적 업데이트 잠금을 가져 오지만 삽입을 수행하기 전에 해제하므로 기본 키 위반이 발생할 수있는 경쟁 조건이 발생합니다. 작업이 원 자성이되도록하려면 암시 ​​적 UPDLOCK 외에 명시 적 HOLDLOCK을 사용해야합니다. 현재로서는 단일 성명으로 보임에도 불구하고 원 자성이 아닙니다.
Triynko 2013

1
MERGE 구문이 잘못되었으며 동일한 작성자의 최근 답변에서 수정되었습니다. stackoverflow.com/a/243670/24472
Larry

21

원하는 기능을 전통적으로 UPSERT라고합니다. 이름을 아는 것만으로도 원하는 것을 찾는 데 도움이 될 수 있습니다.

SQL Server 2005에는이 작업을 수행하는 좋은 방법이 없다고 생각합니다. 2008 년에는 http://www.databasejournal.com/features/mssql/article.php/3739131 또는 http://blogs.conchango.com/davidportas/archive/ 와 같이이를 수행하는 데 사용할 수있는 MERGE 문이 도입되었습니다. 2007 / 11 / 14 / SQL-Server-2008-MERGE.aspx

Merge는 2005 년 베타에서 사용할 수 있었지만 최종 릴리스에서는 제거되었습니다.


18

upsert / merge가하는 일은 효과가 있습니다.

IF EXISTS (SELECT * FROM [Table] WHERE Id = X)
   UPDATE [Table] SET...
ELSE
   INSERT INTO [Table]

따라서 이러한 기사와이 의사 코드의 조합이 상황을 움직일 수 있기를 바랍니다.


10

나는 블로그 포스트를 썼다이 문제에 대한 .

결론은 저렴한 업데이트를 원하고 동시 사용에 대해 안전하려면 다음을 시도하십시오.

update t
set hitCount = hitCount + 1
where pk = @id

if @@rowcount < 1 
begin 
   begin tran
      update t with (serializable)
      set hitCount = hitCount + 1
      where pk = @id
      if @@rowcount = 0
      begin
         insert t (pk, hitCount)
         values (@id,1)
      end
   commit tran
end

이렇게하면 업데이트 작업은 1 개, 삽입 작업은 최대 3 개입니다. 따라서 일반적으로 업데이트하는 경우 안전하고 저렴한 옵션입니다.

동시에 사용하기에 안전하지 않은 것을 사용하지 않도록 매우주의 할 것입니다. 프로덕션에서 기본 키 위반이나 중복 행을 얻는 것은 정말 쉽습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.