แทรกลงในตาราง MySQL หรืออัปเดตถ้ามี


875

ฉันต้องการเพิ่มแถวในตารางฐานข้อมูล แต่หากมีแถวที่มีคีย์เฉพาะเหมือนกันฉันต้องการอัปเดตแถว

ตัวอย่างเช่น:

insert into table (id, name, age) values(1, "A", 19)

สมมติว่าคีย์ที่ไม่ซ้ำกันidและในของฉันฐานข้อมูลid = 1มีแถวที่มี ในกรณีนั้นฉันต้องการอัปเดตแถวนั้นด้วยค่าเหล่านี้ โดยปกติจะทำให้เกิดข้อผิดพลาด
ถ้าฉันใช้insert IGNOREมันจะไม่สนใจข้อผิดพลาด แต่ก็ยังไม่อัปเดต


5
SQL ต้องการไวยากรณ์อย่างเป็นทางการสำหรับกรณีการใช้งานนี้ซึ่งไม่ได้บังคับให้ซ้ำค่าในไวยากรณ์และเก็บรักษาคีย์หลัก
Pete Alvin

เพื่อให้ได้ ID ที่มีอิทธิพลอ้างถึงMySQL ON DUPLICATE KEY - ใส่รหัสล่าสุด?
Kris Roofe

ข้อแม้:ตามรุ่น 5.7 วิธีการนี้ไม่สนับสนุน WHERE clause ซึ่งเป็นส่วนหนึ่งของการดำเนินการ INSERT / UPDATE โดยตรง นอกจากนี้ UPDATE จะนับการดำเนินการที่แยกต่างหากสองรายการ (DELETE และ INSERT) ... ในกรณีที่สำคัญสำหรับวัตถุประสงค์ในการตรวจสอบ (Learnbit)
dreftymac

คำตอบ:


1599

ใช้ INSERT ... ON DUPLICATE KEY UPDATE

ค้นหา:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19

86
+1 จากสิ่งที่ฉันค้นพบวิธีการนี้มีปัญหาน้อยกว่าสำหรับการเพิ่มคีย์อัตโนมัติและการชนคีย์ที่ไม่ซ้ำกันอื่น ๆ กว่า REPLACE INTO และมีประสิทธิภาพมากกว่า
Andrew Ensley

46
ฉันรู้ว่าคุณทุกคนพูดถึงเรื่องนี้ แต่ฉันต้องการที่จะชัดเจนสำหรับคนอื่น ๆ หากรหัสที่คุณแทรกไม่ใช่คีย์หลักหรือ UNIQUE จะไม่สามารถใช้งานได้ สิ่งนี้ไม่ได้ผลสำหรับฉันในตอนแรกเพราะ ID ของฉันไม่ซ้ำกัน
Keven

7
ฉันสงสัยว่าทำไมaffected row countผลลัพธ์2เมื่ออัปเดตแถวเดียว (บนคีย์ซ้ำ) สำเร็จแล้ว ใครมีผลนี้ (ข้อมูลได้รับการปรับปรุงอย่างถูกต้อง: หมายถึงอัปเดตเพียง 1 แถวเท่านั้น)
Dimitry K

15
นี่มันช้าไปหน่อย แต่ต่อไป: มันระบุไว้ในคู่มือว่าการปรับปรุงเพื่อON DUPLICATE KEY UPDATEเพิ่มแถวที่ได้รับผลกระทบโดย 2 มันรายงาน 0 ถ้าไม่มีการปรับปรุงจริง (เหมือนปกติUPDATE)
Vatev

61
โปรดทราบว่าคุณสามารถใช้ค่า (ชื่อ) เพื่ออ้างอิงถึงค่าที่คุณพยายามแทรกเช่นตาราง INSERT INTO (id, ชื่อ, อายุ) ค่านิยม (1, "A", 19) ในการทำซ้ำคีย์ UPDATE ชื่อ = ค่า (ชื่อ) , age = VALUES (อายุ)
Curious Sam

246

ตรวจสอบ REPLACE

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)

11
@Piontek เพราะอันนี้สั้นกว่าและง่ายต่อการเข้าใจและไม่มีใครอธิบายว่าทำไม "การแทรกที่ซ้ำกัน" จึงดีกว่า
Mr_Chimp

77
มันเปลี่ยนรหัสของบันทึกและดังนั้นจึงอาจทำลายการอ้างอิงต่างประเทศ
boh

102
ปัญหาอื่นของ REPLACE INTO คือคุณต้องระบุค่าสำหรับฟิลด์ทั้งหมด ... มิฉะนั้นฟิลด์จะสูญหายหรือถูกแทนที่ด้วยค่าเริ่มต้น แทนที่เป็นหลักจะลบแถวหากมีอยู่แล้วแทรกแถวใหม่ ในตัวอย่างถ้าคุณทำ 'แทนที่ค่าในตาราง (id, อายุ) (1, 19) แล้วฟิลด์ชื่อจะกลายเป็นโมฆะ
Dale

33
นี่เป็นการลบแถวทั้งหมดและดำเนินการ INSERT ใหม่
mjb

8
@mjb ดังนั้นคุณต้องมีสิทธิ์ลบซึ่งเป็นการดีที่ไม่ควรมีหากคุณไม่ต้องการ ผู้ใช้ฐานข้อมูลสภาพแวดล้อมของฉันมีสิทธิ์ INSERT และ UPDATE เท่านั้นดังนั้น REPLACE จะไม่ทำงาน
ndm13

54

เมื่อใช้การแทรกแบบแบ็ตช์ให้ใช้ไวยากรณ์ต่อไปนี้:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...

มีประโยชน์มากถ้าคุณต้องการจัดการกับค่าใหม่
Hunger

หากVALUES(name)ไม่ได้ผลคุณสามารถลองname = 'name_value',...;
Son Pham

26

ลองใช้ดู

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

หวังว่านี่จะช่วยได้


6
จริงๆแล้วฉันไม่จำเป็นต้องเพิ่มค่าใหม่ไปยังแถวอื่นด้วยรหัสใหม่แทนฉันต้องการแทนที่ค่าที่มีอยู่ของ id = 1 ด้วยค่านี้ (ที่ผมเข้าใจเพิ่มขึ้นนี้ประชาชนได้และเพิ่มข้อมูล)
Keshan

49
ฉันไม่คิดว่าเขาต้องการเพิ่มรหัสทีละรายการซ้ำ
Donnie

7
"transgress" ไม่ใช่คำที่คุณมองหา :) น่าเสียดายที่ตอนนี้ฉันเห็น "transgress" ฉันไม่สามารถเห็นภาพคำที่แท้จริงได้อีกต่อไป ..
mwfearnley

1
คุณกำลังมองหา "traverses" หรือ "covers" หรือไม่?
Chris Dev

4
@mwfearnley คำที่คุณพยายามนึกภาพคือ "ฟันฝ่า" ใช้เวลาหนึ่งปีครึ่ง :-)
Michael Krebs

20

ลองสิ่งนี้:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

หมายเหตุ: ที่
นี่หาก id เป็นคีย์หลักหลังจากนั้นการแทรกครั้งแรกid='1'ทุกครั้งที่พยายามแทรกid='1'จะอัปเดตชื่อและอายุและอายุชื่อก่อนหน้านี้จะเปลี่ยนไป


ผมต้องการที่จะทำงานโดยไม่ต้องใช้รหัส คุณเคยลองโดยไม่ใช้รหัสหลักหรือไม่?
ersks

@ersks ดูคำถาม ผู้ใช้ถามถึงเมื่อมีคีย์ที่ไม่ซ้ำกัน
Rasel

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

15
INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

โซลูชันทั้งหมดเหล่านี้จะทำงานเกี่ยวกับคำถามของคุณ

หากคุณต้องการทราบรายละเอียดเกี่ยวกับคำแถลงเหล่านี้โปรดไปที่ลิงค์นี้


REPLACEไม่มีการบันทึกไว้ในเอกสารที่เชื่อมโยง
Ray Baxter

ข้อความค้นหา sql เต็มไปด้วยความผิดพลาดตัวอย่างของคุณจะไม่ทำงาน มันคือ INSERT INTO TABLE (ไม่ใช่ INTO TABLE) และ ON DUPLICATE KEY UPDATE (ไม่ใช่ ON DUPLICATE UPDATE SET) ไม่แน่ใจว่าใครเป็นผู้อัปโหลดสิ่งนี้
Robert Sinclair

1
ขออภัยสำหรับข้อผิดพลาดที่พิมพ์ผิด ขอบคุณสำหรับการแก้ไขฉัน
Dilraj Singh

11

เมื่อใช้ SQLite:

REPLACE into table (id, name, age) values(1, "A", 19)

โดยมีเงื่อนไขว่าidเป็นคีย์หลัก มิฉะนั้นมันก็แทรกแถวอื่น ดูINSERT (SQLite)


สิ่งที่replace into"แทรกเข้าหรือปรับปรุงเมื่อมีอยู่" คืออะไร @Owl
DawnSong

+1 (1 จาก 3) ฉันพบว่าสิ่งนี้ทำงานได้กับสถานการณ์ของฉัน - ฉันต้องการแทนที่แถวที่มีอยู่ด้วยคีย์เฉพาะหรือถ้าไม่มีก็เพิ่มแถว วิธีแก้ปัญหาที่ง่ายที่สุดที่นี่
therobyouknow

(2 จาก 3) ข้อความค้นหาของฉัน:CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW();
therobyouknow

(3 จาก 3) คำถาม / คำตอบที่เกี่ยวข้องstackoverflow.com/questions/41767517/…
therobyouknow

2
ปัญหานี้ใน mysql คือการแทนที่จะลบค่าอื่น ๆ ในกรณีที่พวกเขาไม่ได้ให้ อย่างไรก็ตามโซลูชัน @ fabiano-souza นั้นเหมาะสมกว่า
Quamber Ali

11

เพียงเพราะฉันอยู่ที่นี่กำลังมองหาวิธีแก้ปัญหานี้ แต่สำหรับการปรับปรุงจากตารางที่มีโครงสร้างเหมือนกัน (ในกรณีของฉันเว็บไซต์ทดสอบฐานข้อมูลเพื่อ DB สด):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

ดังที่กล่าวไว้ในที่อื่นเฉพาะคอลัมน์ที่คุณต้องการอัปเดตเท่านั้นที่จะต้องรวมหลังจากนั้น ON DUPLICATE KEY UPDATEนั้น

ไม่จำเป็นต้องแสดงรายการคอลัมน์ใน INSERTหรือSELECTแม้ว่าฉันเห็นด้วยว่าอาจเป็นวิธีปฏิบัติที่ดีกว่า


4

ในกรณีที่คุณต้องการให้non-primaryเขตข้อมูลเป็นเกณฑ์ / เงื่อนไขในการON DUPLICATEที่คุณสามารถสร้างความสำคัญเกี่ยวกับตารางที่ที่จะเรียกUNIQUE INDEXDUPLICATE

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

และในกรณีที่คุณต้องการรวมสองฟิลด์เพื่อทำให้เป็นเอกลักษณ์บนตารางคุณสามารถทำได้โดยเพิ่มพารามิเตอร์เพิ่มเติมตัวสุดท้าย

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

หมายเหตุเพียงตรวจสอบให้แน่ใจว่าได้ลบข้อมูลทั้งหมดที่มีค่าnameและageค่าเท่ากันก่อนอื่นทั้งหมด

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

หลังจากนั้นก็จะทำให้เกิดON DUPLICATEเหตุการณ์

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)

2

ในกรณีของฉันฉันสร้างแบบสอบถามด้านล่าง แต่ในแบบสอบถามแรกถ้าid1 มีอยู่แล้วและอายุอยู่ที่นั่นแล้วหลังจากนั้นถ้าคุณสร้างแบบสอบถามแรกโดยไม่ageเกินมูลค่าของageจะไม่มี

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

สำหรับการหลีกเลี่ยงปัญหาด้านบนให้สร้างเคียวรีตามด้านล่าง

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

มันอาจจะช่วยคุณ ...


2
ไม่มีใครรู้ว่าทำไมเราต้องกำหนดค่าสองครั้งหรือไม่ ทำไม MySQL ไม่อนุญาตให้เราสิ้นสุดการค้นหาที่ ON DUPLICATE KEY UPDATE โดยไม่ต้องทำซ้ำคำสั่งมอบหมายทั้งหมด? บางตารางฐานข้อมูลมีหลายคอลัมน์และดูเหมือนว่าซ้ำซ้อน / ฟรี ฉันเข้าใจว่าทำไมเราถึงมีตัวเลือกสำหรับการมอบหมายทางเลือก แต่ทำไมไม่มีตัวเลือกในการละเว้นพวกเขาเช่นกัน แค่อยากรู้ถ้าใครรู้
น้ำทะเลสีฟ้า

2

ในกรณีที่คุณต้องการเก็บฟิลด์เก่าไว้ (เช่น: ชื่อ) แบบสอบถามจะเป็น:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.