web-dev-qa-db-ja.com

存在しない場合は同時に挿入

ストアドプロシージャへの挿入で同時実行の問題が発生しています。手順の関連部分は次のとおりです。

select @_id = Id from table1 where othervalue = @_othervalue
IF( @_id IS NULL)
BEGIN
    insert into table1 (othervalue) values (@_othervalue)
    select @_id = Id from table1 where othervalue = @_othervalue
END

これらのストアドプロシージャの3つまたは4つを同時に実行すると、複数の挿入が発生することがあります。

私はこれを次のように修正することを計画しています:

insert into table1 (othervalue) 
    select TOP(1) @_othervalue as othervalue from table1 WITH(UPDLOCK) 
    where NOT EXISTS ( select * from table1 where othervalue = @_othervalue )

select @_id = Id from table1 where othervalue = @_othervalue

問題は、SQLサーバーに重複せずに同時に挿入する方法ですか? TOPを使用して挿入する必要があるのは、邪魔になるだけです。

13
Chris

serializableヒントを使用してmergeステートメントを使用できます。

merge table1 with (serializable) as T 
using (select @_othervalue as othervalue) as S
on T.othervalue = S.othervalue
when not matched then
  insert (othervalue) values (othervalue);
7
Mikael Eriksson

「othervalue」列で重複を望まない場合は、unique constraintその列。クエリは次のようになります。

 ALTER TABLE table1
 ADD CONSTRAINT unique_c_othervalue UNIQUE(othervalue)

クエリが 'othervalue'列に重複する値を挿入しようとした場合、これはエラーを返します。

5
StanleyJohns

@StanleyJohnsが推奨するような一意の制約を使用します。次に、挿入ステートメントをBEGIN TRY END TRYで囲みます。

select @_id = Id from table1 where othervalue = @_othervalue
IF( @_id IS NULL)
BEGIN
    BEGIN TRY
        insert into table1 (othervalue) values (@_othervalue)
        select @_id = Id from table1 where othervalue = @_othervalue        
    END TRY
    BEGIN CATCH
        select @_id = Id from table1 where othervalue = @_othervalue        
    END CATCH
END
2
mrdenny