Chèn nếu không tồn tại, đồng thời


13

Tôi đang gặp vấn đề tương tranh với các phần chèn của mình trong một thủ tục được lưu trữ. Phần có liên quan của thủ tục là đây:

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

Khi chúng tôi chạy đồng thời 3 hoặc 4 trong số các Proc được lưu trữ này, chúng tôi sẽ nhận được nhiều lần chèn.

Tôi đang lên kế hoạch sửa lỗi này như vậy:

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

Câu hỏi là, làm thế nào để chèn đồng thời mà không trùng lặp trong máy chủ sql? Thực tế là tôi phải sử dụng TOP để chỉ chèn một lần làm phiền tôi.


1
Bạn không phải sử dụng TOP. Xóa tham chiếu bảng TỪ khỏi câu lệnh CHỌN.
ErikE


@GSerg Tôi nghĩ bạn đúng.
Chris

Câu trả lời:


7

Bạn có thể sử dụng một tuyên bố hợp nhất với serializablegợi ý.

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);

Bạn có căng thẳng kiểm tra cách tiếp cận của bạn từ hai hoặc nhiều kết nối?
AK

2
@AlexKuznetsov - Tôi đã làm điều đó một thời gian trước cho một câu hỏi khác về SO. Tôi đã sử dụng hai tab trong SSMS. Đầu tiên đã thử nghiệm insert ... where not exist ...mô hình và thấy rằng bạn có thể gặp bế tắc và vi phạm khóa, do đó cần phải sử dụng updlock và tuần tự hóa. Sau đó, tôi đã thử nghiệm tuyên bố hợp nhất và nghĩ rằng nó sẽ xử lý mọi thứ tốt hơn một chút và nó đã làm được vì ở đó không có bế tắc nhưng tôi vẫn phải sử dụng tuần tự hóa để không vi phạm chính.
Mikael Eriksson

1
Đây là một câu trả lời thực sự tuyệt vời.
Chris Marisic

5

Nếu bạn không muốn trùng lặp trên cột 'othervalue', bạn có thể làm như vậy bằng cách tạo một unique constraintcột trên cột đó. Truy vấn sẽ là:

 ALTER TABLE table1
 ADD CONSTRAINT unique_c_othervalue UNIQUE(othervalue)

Điều này sẽ trả về một lỗi nếu một truy vấn cố gắng chèn một giá trị trùng lặp vào cột 'othervalue'.


Làm thế nào điều đó sẽ làm việc nếu ràng buộc duy nhất là một tuple hai hàng?
Chris

1
@Chris Làm thế nào để bạn có một ràng buộc duy nhất kéo dài các hàng?
Aaron Bertrand

@Aaron Tôi có thể tắt thuật ngữ của mình, nhưng chúng tôi có hai hàng cùng nhau cần phải là duy nhất. Tôi không nghĩ rằng nó được thi hành trong lược đồ của chúng tôi.
Chris

2

Sử dụng một ràng buộc duy nhất như @StanleyJohns khuyến nghị. Sau đó sử dụng BEGIN TRY END TRY xung quanh câu lệnh chèn của bạn.

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.