แทรกถ้าไม่มีอยู่พร้อมกัน


13

ฉันกำลังมีปัญหาการใช้งานพร้อมกันกับส่วนแทรกในขั้นตอนการจัดเก็บ ส่วนที่เกี่ยวข้องของขั้นตอนนี้คือ:

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

เมื่อเรารัน proc ที่เก็บไว้ 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 เพื่อแทรกเมื่อรบกวนฉันเท่านั้น


1
คุณไม่จำเป็นต้องใช้ TOP ลบการอ้างอิงตาราง FROM จากคำสั่ง SELECT
ErikE


@ GSG ฉันคิดว่าคุณถูกต้อง
Chris

คำตอบ:


7

คุณสามารถใช้คำสั่งผสานกับserializableคำใบ้

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

คุณเครียดทดสอบวิธีการของคุณจากสองคนหรือมากกว่านั้น?
AK

2
@AlexKuznetsov - ฉันทำไปซักพักแล้วสำหรับคำถามอื่นใน SO ฉันใช้สองแท็บใน SSMS ก่อนทดสอบinsert ... where not exist ...รูปแบบและพบว่าคุณจะได้รับการหยุดชะงักและการละเมิดที่สำคัญดังนั้นจึงมีความจำเป็นต้องใช้ updlock และต่อเนื่องได้ จากนั้นฉันทดสอบคำสั่งผสานและคิดว่ามันจะจัดการกับสิ่งต่าง ๆ ได้ดีขึ้นเล็กน้อยและมันทำเพราะไม่มีการหยุดชะงัก แต่ฉันยังต้องใช้ซีเรีย
Mikael Eriksson

1
นี่เป็นคำตอบที่ยอดเยี่ยมจริงๆ
Chris Marisic

5

หากคุณไม่ต้องการให้ซ้ำกันในคอลัมน์ 'othervalue' คุณสามารถทำได้โดยการสร้างunique constraintในคอลัมน์นั้น แบบสอบถามจะเป็น:

 ALTER TABLE table1
 ADD CONSTRAINT unique_c_othervalue UNIQUE(othervalue)

การทำเช่นนี้จะทำให้เกิดข้อผิดพลาดหากแบบสอบถามพยายามแทรกค่าที่ซ้ำกันลงในคอลัมน์ 'othervalue'


มันจะทำงานอย่างไรถ้าข้อ จำกัด ที่ไม่เหมือนใครคือทูเปิลสองแถว
Chris

1
@Chris คุณมีข้อ จำกัด เฉพาะที่ครอบคลุมแถวได้อย่างไร
Aaron Bertrand

@ แอรอนฉันอาจจะมีคำศัพท์ของฉันออกไป แต่เรามีสองแถวที่จะต้องไม่ซ้ำกัน ฉันไม่คิดว่ามันจะถูกบังคับใช้ในสคีมาของเรา
Chris

2

ใช้ข้อ จำกัด เฉพาะเช่น @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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.