วิธีแทรกหรืออัปเดตโดยใช้ข้อความค้นหาเดียว


25

ฉันมีตารางทดสอบที่มีคอลัมน์ id ซึ่งเป็นคีย์หลักและเพิ่มขึ้นอัตโนมัติและชื่อ ฉันต้องการที่จะแทรกบันทึกใหม่ถ้า annd เฉพาะในกรณีที่ไม่มีบันทึกตัวอย่างเช่น

อินพุตคือ id = 30122 และ name = john

หากมีการบันทึกที่มี id 30122 ฉันได้อัปเดตคอลัมน์ชื่อเป็น john หากไม่มีการบันทึกฉันจะใส่บันทึกใหม่

ฉันสามารถทำได้โดยใช้ 2 แบบสอบถามเช่น

select * from test where id=30122

หากมีบางบันทึกฉันสามารถใช้งานได้ update test set name='john' where id=3012

หรือถ้ามันไม่มีบันทึกฉันก็สามารถใช้งานได้

insert into test(name) values('john')

แต่ฉันต้องการใช้ข้อความค้นหาเดียว?

ใครสามารถบอกได้ถ้าเป็นไปได้?


1
But I wanted to use single query?ทำไม?
Aaron Bertrand

@AaronBertrand ปลายด้านหลังของฉันได้รับการพัฒนาโดยใช้ java.So ถ้าฉันใช้ 2 quries แล้วฉันต้องกด DB 2 ครั้งดังนั้นถ้ามันสามารถทำได้โดยใช้แบบสอบถามเดียวแล้วทำไมต้องใช้ 2 แบบสอบถาม
SpringLearner

1
Java ไม่รองรับโพรซีเดอร์ที่เก็บไว้หรือแบทช์เดี่ยวที่มีสองคำสั่งที่ต้องการการเข้าถึงฐานข้อมูลเพียงครั้งเดียว
Aaron Bertrand

@AaronBertrand คุณสามารถยกตัวอย่างว่าคุณจะจัดการกับ sql server 2008 หรือใหม่กว่าได้อย่างไร
eaglei22

1
@ eaglei22 ฉันจะใช้ตัวอย่างที่ 2 ในคำตอบของ vijayp ด้านล่าง ฉันจะยังคงไม่เลือกMERGEในรุ่นใด ๆ แม้ SQL Server 2019 พื้นหลังบางอย่างเกี่ยวกับที่นี่
Aaron Bertrand

คำตอบ:


41

คุณสามารถลองสิ่งนี้

IF EXISTS(select * from test where id=30122)
   update test set name='john' where id=3012
ELSE
   insert into test(name) values('john');

แนวทางอื่นเพื่อประสิทธิภาพที่ดีกว่าคือ

update test set name='john' where id=3012
IF @@ROWCOUNT=0
   insert into test(name) values('john');

และอ่านนิสัยที่ไม่ดีนี้เพื่อเริ่มต้นด้วยคำนำหน้าสคี


4
ตัวอย่างแรกนั้นสิ้นเปลืองและมักจะนำไปสู่การหยุดชะงัก - ฉันจะไม่แนะนำเลย
Aaron Bertrand

@AaronBertrand สนใจที่จะทำอย่างละเอียด? ขอบคุณ
Hexo

5
@SlapY แน่นอนว่าในตัวอย่างแรกคุณพูดว่า: "เฮ้, SQL Server มีแถวที่มี ID นี้หรือไม่?" SQL Server ออกไปเพื่อค้นหาแถวบางทีใช้การสแกนแล้วกลับมาพร้อมคำตอบ "ทำไมใช่ผู้ใช้ฉันมีแถวที่มี ID นั้น!" จากนั้นคุณพูดว่า "โอเค SQL Server ไปหาแถวนั้นอีกครั้งแต่คราวนี้อัปเดต!" คุณเห็นว่าการค้นหาหรือสแกนสองครั้งนั้นสิ้นเปลืองหรือไม่ คุณสามารถจินตนาการว่าจะเกิดอะไรขึ้นหากผู้ใช้รายอื่นถามคำถามเดียวกันเกี่ยวกับการมีอยู่ของ SQL Server ก่อนที่คุณจะย้ายไปทำอะไรกับมัน
Aaron Bertrand

ขอบคุณฉันไม่เห็นว่าทำไมคนแรกที่ถูกคุกคามให้หยุดชะงักในขณะที่คนที่สองไม่ใช่? ทั้งสองประกอบด้วยหลายงบที่สามารถดักจับถ้าไม่ทำงานด้วยการล็อคเต็ม ฉันผิดหรือเปล่า?
Hexo

2
@ 0x25b3 ไม่ใช่ว่าจะมีคนถูกคุกคามจากการหยุดชะงักและอีกคนไม่ได้เป็นเช่นนั้นตัวอย่างแรกมีแนวโน้มที่จะเป็นเช่นนั้น คุณควรจะทำธุรกรรมอย่างเต็มรูปแบบและเหมาะสมในทั้งสองกรณี แต่ผู้คนก็ไม่ทำเช่นนั้น ...
Aaron Bertrand

17

สมมติว่า SQL Server 2008 หรือใหม่กว่าคุณสามารถใช้MERGE:

ตาราง

CREATE TABLE dbo.Test
(
    id integer NOT NULL,
    name varchar(30) NULL,

    CONSTRAINT PK_dbo_Test__id
        PRIMARY KEY CLUSTERED (id)
);

สอบถาม

MERGE dbo.Test WITH (SERIALIZABLE) AS T
USING (VALUES (3012, 'john')) AS U (id, name)
    ON U.id = T.id
WHEN MATCHED THEN 
    UPDATE SET T.name = U.name
WHEN NOT MATCHED THEN
    INSERT (id, name) 
    VALUES (U.id, U.name);

SERIALIZABLEคำใบ้เป็นสิ่งจำเป็นสำหรับการดำเนินงานที่ถูกต้องภายใต้การทำงานพร้อมกันสูง

คุณสามารถค้นหาการเปรียบเทียบของวิธีการทั่วไปโดย Michael J. Swart ที่นี่:

Mythbusting: การแก้ไข / ปรับปรุงพร้อมกัน


8
ผสานมีปัญหาบางอย่าง
vonPryz

การเชื่อมโยงที่เป็นตำนานมียอดเยี่ยม ทำได้ดีนี่!
JonnyRaa
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.