2008-08-01 9 views
69

MySQLには、この非常に便利で適切なSQLコマンドREPLACE INTOがあります。SQL Server 2005のMySQL REPLACE INTOへの実装?

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

、新しいトランザクションの開始Select()をやって、その後のいずれかUPDATEまたはINSERTCOMMITは、アプリケーションでそれをやって、したがって、常に文の2つのバージョンを維持する場合は特に、常に痛みを少しです。

universalこのような機能をSQL Server 2005に実装する方法があるのだろうか?

答えて

53

これはMSSQL(rant on my blog)について私を悩ますものです。私はMSSQLがupsertをサポートすることを願っています。 Dillie-Oのコード@

が古いSQLのバージョン(1票)で良い方法ですが、それはまだ基本的に2つのIO操作(exists、その後updateまたはinsert)である

わずかに良い方法がありますthis postに、基本的に:それは更新かどう

--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のインサート。

MS SQL2008は、SQLからmergeを紹介: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操作だが、ひどいコード

+0

すばらしい、ありがとう!選択を保存し、しばしば更新と "私"の挿入の間にそのキーのための他の挿入がないことを確かめることができる状況では、teransactionは必要ありません。 –

+1

@Michaelこのソリューションを使用する場合は、このテーブルにユニークなインデックスを持ち、重複したキーエラーを処理する方がよいでしょう。 –

+3

@Keithマージステートメントが機能しません。 'MERGE'は' WHERE'節をサポートしていないので、 'USING'と' ON'を使って書き直す必要があります。また、 'WITH(HOLDLOCK)'を追加しない限り、レースがあり、同時にINSERTが発生する可能性があります。キー衝突のためにそれらのいずれかが失敗する可能性があります。 –

19

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

SQL Server 2005にはこれを行うための優れた方法はないと思います。 2008年には、これを達成するために使用できるMERGEステートメントが紹介されています。またはhttp://blogs.conchango.com/davidportas/archive/2007/11/14/SQL-Server-2008-MERGE.aspx

マージは2005年のベータ版で利用できましたが、最終リリースでは削除されました。アップサート/マージが何をしているか

15

だからうまくいけば、これらの記事の組み合わせと、この擬似コードは、物事を動かすことができ

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

...の効果に何かです。

9

:-(私はblog post about this issueを書いた

要するに、安価なアップデートが必要な場合、同時に使用する場合は安全であることを望む場合です。試してみてください:try:

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つの操作があります。あなたが一般的に更新している場合、これは安全な安いオプションです。

また、同時に使用するには安全でないものを使用しないように注意します。本番環境での主キー違反や重複行を取得するのは簡単です。

関連する問題