ฉันจะอัพเดทหากมีอยู่แทรกถ้าไม่ (AKA“ upsert” หรือ“ ผสาน”) ใน MySQL?


คำตอบ:


191

INSERT ... ON DUPLICATE KEY UPDATEใช้ ตัวอย่างเช่น:

INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1

10
ใช่ผมเชื่อว่าเทียบเท่าของ SQL Server MERGEจะเรียกว่า "UPSERT"โดยทั่วไปแนวคิดมักจะถูกเรียกว่า
ความวุ่นวาย

3
@blub: หากคุณสร้างคีย์เฉพาะขึ้นมาgebและtopicมันจะใช้ได้ ( ALTER TABLE table ADD UNIQUE geb_by_topic (geb, topic))
ความวุ่นวาย

1
@Brian: เรียกว่าเทียบเท่าของ Oracle MERGEแต่ฉันไม่แน่ใจว่าไวยากรณ์นั้นเหมือนกับ SQL Server หรือไม่
Ken Keenan

1
@Brooks: ถ้าคุณส่ง 0 มันจะใช้ 0 เป็นค่าจริง ดังนั้นอย่าทำอย่างนั้น อย่าผ่านมันหรือผ่านมันNULLไปเพื่ออนุญาตให้auto_incrementพฤติกรรมทำงานได้ (ซึ่งเป็นอย่างอื่นใช่ทำงานได้ตามที่คุณเห็นดูที่dev.mysql.com/doc/refman/5.5/th/example-auto-increment html )
ความโกลาหล

3
ขอบคุณและคุณสามารถใช้VALUES(col)เพื่อรับค่าจากอาร์กิวเมนต์การแทรกในกรณีที่ซ้ำกัน เช่น:ON DUPLICATE UPDATE b = VALUES(b), c = VALUES(c)
gerrytan

5

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ Google นำฉันมาที่นี่เมื่อเร็ว ๆ นี้ดังนั้นฉันจึงจินตนาการว่ามีคนอื่นมาที่นี่ด้วย

@chaos ถูกต้อง: มีINSERT ... ON DUPLICATE KEY UPDATEไวยากรณ์

อย่างไรก็ตามคำถามเดิมถามเกี่ยวกับ MySQL โดยเฉพาะและใน MySQL มีREPLACE INTO ...ไวยากรณ์ IMHO คำสั่งนี้ง่ายและตรงไปตรงมาสำหรับการใช้งาน จากคู่มือ:

REPLACE ทำงานเหมือนกับ INSERT ยกเว้นว่าหากแถวเก่าในตารางมีค่าเหมือนกับแถวใหม่สำหรับคีย์หลักหรือดัชนี UNIQUE แถวเก่าจะถูกลบก่อนที่จะแทรกแถวใหม่

หมายเหตุนี่ไม่ใช่ SQL มาตรฐาน ตัวอย่างจากคู่มือ:

CREATE TABLE test (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64) DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)

mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)

mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)

แก้ไข:เพียงแค่เตือนว่าไม่เหมือนREPLACE INTO UPDATEดังที่คู่มือบอกREPLACEลบแถวถ้ามีอยู่แล้วแทรกใหม่ (หมายเหตุตลก "2 แถวได้รับผลกระทบ" ในตัวอย่างข้างต้น.) นั่นคือมันจะเข้ามาแทนที่ค่าของทุกคอลัมน์ของการบันทึกที่มีอยู่ (และไม่เพียงปรับปรุงบางคอลัมน์.) พฤติกรรมของ MySQL ที่REPLACE INTOเป็นเหมือนที่ INSERT OR REPLACE INTOSqlite ดูคำถามนี้สำหรับวิธีแก้ไขปัญหาเฉพาะบางอย่างหากคุณต้องการอัปเดตคอลัมน์บางคอลัมน์เท่านั้น (และไม่ใช่ทุกคอลัมน์) หากมีระเบียนอยู่แล้ว

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