MySQL REPLACEINTOのSQLServer 2005実装?


86

MySQLには、この信じられないほど便利でありながら独自仕様のREPLACE INTOSQLコマンドがあります。

これはSQLServer 2005で簡単にエミュレートできますか?

新しいトランザクションを開始し、Select()次にaを実行し、次にUPDATEorまたはINSERTandCOMMITを実行することは、特にアプリケーションで実行する場合は常に少し面倒です。したがって、ステートメントの2つのバージョンを常に保持します。

そのような関数をSQLServer 2005に実装する簡単で普遍的な方法があるのだろうか?

回答:


60

これはMSSQLについて私を悩ませるものです(私のブログで暴言を吐きます)。MSSQLがサポートされてupsertいることを望みます。

@ Dillie-Oのコードは古いSQLバージョン(+1投票)では良い方法ですが、それでも基本的に2つのIO操作(the exists、次にupdateor 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', ... )

これにより、更新の場合は1つのIO操作に、挿入の場合は2つのIO操作に削減されます。

MS Sql2008mergeは、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, ... )

今では実際には1つのIO操作ですが、ひどいコードです:-(


まことにありがとうございます!選択を保存し、更新と「自分の」挿入の間にそのキーの他の挿入がないことを確認できる状況では、多くの場合、中断を必要としません。
MichaelStum

2
@Michaelこのソリューションを使用する場合は、このテーブルに一意のインデックスを設定し、重複キーエラーを処理することをお勧めします。
サムサフラン

3
@Keithマージステートメントが機能しません。MERGEはこのWHERE句をサポートしていません。とを使用して書き直す必要がUSINGありONます。また、を追加しない限りWITH (HOLDLOCK)、競合INSERTが発生し、キーの衝突が原因でそのうちの1つが失敗する同時発生が発生する可能性があります。
Evgeniy Berezovsky 2013

はい、ここで指摘されているように:weblogs.sqlteam.com/dang/archive/2009/01/31/…MERGEはアトミックではありません。暗黙の更新ロックを取得しますが、挿入を実行する前に解放します。これにより、競合状態が発生し、主キー違反が発生する可能性があります。操作をアトミックにするには、暗黙的なUPDLOCKに加えて明示的なHOLDLOCKを使用する必要があります。現状では、単一のステートメントのように見えますが、アトミックではありません。
Triynko 2013年

1
MERGE構文が間違っており、同じ作成者からの最近の回答で修正されています:stackoverflow.com/a/243670/24472
Larry

21

あなたが探している機能は、伝統的にUPSERTと呼ばれています。それが何と呼ばれるかを少なくとも知っていると、探しているものを見つけるのに役立つかもしれません。

SQL Server2005にはこれを行うための優れた方法はないと思います。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

マージは2005年のベータ版で利用可能でしたが、最終リリースで削除されました。


18

アップサート/マージが行っていることは、次のような効果があります...

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.