หลายคนจะแนะนำให้คุณใช้MERGE
แต่ฉันเตือนให้คุณต่อต้าน โดยค่าเริ่มต้นจะไม่ปกป้องคุณจากการเกิดพร้อมกันและสภาพการแข่งขันมากกว่างบหลายและมันจะแนะนำอันตรายอื่น ๆ :
http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/
แม้จะมีไวยากรณ์ "เรียบง่าย" นี้ฉันยังคงชอบวิธีนี้ (ไม่จัดการข้อผิดพลาดเนื่องจากความกะทัดรัด):
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
UPDATE dbo.table SET ... WHERE PK = @PK;
IF @@ROWCOUNT = 0
BEGIN
INSERT dbo.table(PK, ...) SELECT @PK, ...;
END
COMMIT TRANSACTION;
ผู้คนมากมายจะแนะนำวิธีนี้:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
IF EXISTS (SELECT 1 FROM dbo.table WHERE PK = @PK)
BEGIN
UPDATE ...
END
ELSE
INSERT ...
END
COMMIT TRANSACTION;
แต่ทั้งหมดนี้สำเร็จคือการทำให้แน่ใจว่าคุณอาจต้องอ่านตารางสองครั้งเพื่อค้นหาแถวที่จะปรับปรุง ในตัวอย่างแรกคุณจะต้องค้นหาแถวครั้งเดียวเท่านั้น (ในทั้งสองกรณีหากไม่พบแถวจากการอ่านเริ่มต้นจะมีการแทรกเกิดขึ้น)
คนอื่น ๆ จะแนะนำวิธีนี้:
BEGIN TRY
INSERT ...
END TRY
BEGIN CATCH
IF ERROR_NUMBER() = 2627
UPDATE ...
END CATCH
อย่างไรก็ตามนี่เป็นปัญหาหากไม่มีเหตุผลอื่นนอกจากให้ SQL Server ตรวจจับข้อยกเว้นที่คุณสามารถป้องกันได้ตั้งแต่แรกนั้นมีราคาแพงกว่ามากยกเว้นในสถานการณ์ที่ไม่ค่อยพบซึ่งแทบทุกครั้งจะล้มเหลว ฉันพิสูจน์ได้มากที่นี่: