การใช้งาน SQL Server 2005 ของ MySQL REPLACE INTO?


87

MySQL มีREPLACE INTOคำสั่ง SQL ที่มีประโยชน์อย่างเหลือเชื่อ แต่เป็นกรรมสิทธิ์

สิ่งนี้สามารถจำลองได้อย่างง่ายดายใน SQL Server 2005 หรือไม่?

การเริ่มต้นธุรกรรมใหม่การทำSelect()และหลังจากนั้นอย่างใดอย่างหนึ่งUPDATEหรือINSERTและCOMMITมักจะเจ็บปวดเล็กน้อยโดยเฉพาะอย่างยิ่งเมื่อทำในแอปพลิเคชันดังนั้นจึงต้องเก็บคำสั่ง 2 เวอร์ชันไว้เสมอ

ฉันสงสัยว่ามีวิธีที่ง่ายและเป็นสากลในการนำฟังก์ชันดังกล่าวไปใช้ใน SQL Server 2005 หรือไม่?

คำตอบ:


60

นี่คือสิ่งที่ทำให้ฉันรำคาญเกี่ยวกับ MSSQL ( พร่ำเพ้อในบล็อกของฉัน ) ฉันหวังว่า MSSQL upsertสนับสนุน

รหัสของ @ Dillie-O เป็นวิธีที่ดีใน SQL เวอร์ชันเก่า (+1 โหวต) แต่ก็ยังคงเป็นการดำเนินการ IO สองรายการ ( existsจากนั้นupdateหรือ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', ... )

ซึ่งจะลดการดำเนินการ IO หนึ่งรายการหากเป็นการอัปเดตหรือสองครั้งหากเป็นการแทรก

MS Sql2008 แนะนำmergeจากมาตรฐาน 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, ... )

ตอนนี้มันเป็นเพียงการดำเนินการ IO เพียงครั้งเดียว แต่รหัสที่แย่มาก :-(


เยี่ยมมากขอบคุณ! บันทึกการเลือกและมักไม่จำเป็นต้องมีการส่งข้อมูลในสถานการณ์ที่ฉันมั่นใจได้ว่าระหว่างการอัปเดตและส่วนแทรก "ของฉัน" ไม่มีส่วนแทรกอื่นสำหรับคีย์นั้น
Michael Stum

2
@ ไมเคิลคุณควรมีดัชนีที่ไม่ซ้ำกันบนตารางนี้และจัดการข้อผิดพลาดของคีย์ที่ซ้ำกันหากคุณจะใช้โซลูชันนี้
Sam Saffron

3
@Keith คำสั่งผสานของคุณไม่ได้ผล MERGEไม่รองรับWHEREอนุประโยคคุณต้องเขียนใหม่โดยใช้USINGและON. นอกจากนี้หากคุณไม่เพิ่มWITH (HOLDLOCK)อาจมีการแข่งขันและเกิดขึ้นพร้อมกันINSERTโดยหนึ่งในนั้นล้มเหลวเนื่องจากการปะทะกันที่สำคัญ
Evgeniy Berezovsky

ใช่ตามที่ระบุไว้ที่นี่: weblogs.sqlteam.com/dang/archive/2009/01/31/… MERGE ไม่ใช่อะตอม จะนำการล็อกการอัปเดตโดยปริยายออก แต่จะปลดล็อกก่อนที่จะทำการแทรกซึ่งทำให้เกิดสภาวะการแย่งชิงที่อาจส่งผลให้เกิดการละเมิดคีย์หลัก คุณต้องใช้ HOLDLOCK อย่างชัดเจนนอกเหนือจาก UPDLOCK โดยนัยเพื่อให้การดำเนินการเป็นแบบปรมาณู ตามที่กล่าวมามันไม่ใช่ปรมาณูแม้ว่าจะดูเหมือนเป็นคำสั่งเดียวก็ตาม
Triynko

1
ไวยากรณ์ MERGE ไม่ถูกต้องและได้รับการแก้ไขในคำตอบล่าสุดจากผู้เขียนคนเดียวกัน: stackoverflow.com/a/243670/24472
Larry

21

ฟังก์ชันที่คุณกำลังมองหานั้นเรียกกันตามเนื้อผ้าว่า UPSERT อย่างน้อยการรู้ว่ามันเรียกว่าอะไรอาจช่วยให้คุณพบสิ่งที่คุณกำลังมองหา

ฉันไม่คิดว่า SQL Server 2005 มีวิธีที่ยอดเยี่ยมในการทำเช่นนี้ 2008 แนะนำคำสั่ง MERGE ที่สามารถใช้เพื่อบรรลุเป้าหมายดังที่แสดงใน: http://www.databasejournal.com/features/mssql/article.php/3739131หรือhttp://blogs.conchango.com/davidportas/archive/ 2007/11/14 / SQL-Server-2008-MERGE.aspx

Merge พร้อมใช้งานในรุ่นเบต้าของปี 2548 แต่พวกเขาได้ลบออกในรุ่นสุดท้าย


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.