CREATE TABLE menus (
id TINYINT(4) NOT NULL AUTO_INCREMENT,
label VARCHAR(10),
url VARCHAR(20),
UNIQUE KEY (id)
);
INSERT INTO menus (label,url) VALUES
('Home','home.html'),
('About us','aboutus.html'),
('Services','services.html'),
('Feedback','feedback.html');
-- 嘗試插入重複 id=4
INSERT INTO menus (id,label,url) VALUES (4,'Contact us','contactus.html');
-- ERROR 1062 (23000): Duplicate entry '4' for key 'id'
INSERT IGNORE INTO menus (id,label,url) VALUES (4,'Contact us','contactus.html'); -- Query OK, 0 rows affected (0.00 sec) SELECT * FROM menus; -- id=4 仍為 'Feedback',新數據被忽略
特點:不報錯、不寫入、不影響自增值、批量導入時單行失敗不中斷整體。
INSERT INTO menus (id,label,url) VALUES (4,'Contact us','contactus.html') ON DUPLICATE KEY UPDATE label='Contact us', url='contactus.html'; -- Query OK, 2 rows affected (0.01 sec) SELECT * FROM menus; -- id=4 已更新為 'Contact us'
特點:檢測到唯一鍵衝突自動轉為 UPDATE,rows affected 返回 2(1 insert + 1 update)。
| 維度 | INSERT IGNORE | ON DUPLICATE KEY UPDATE |
|---|---|---|
| 語義 | 「不存在則插入」 | 「不存在插入,存在則更新」 |
| 數據結果 | 保留舊值 | 覆蓋為新值 |
| 返回行數 | 0(忽略) | 1(新增) 或 2(更新) |
| 自增值 | 不消耗 | 不消耗 |
| 適用場景 | 去重導入、日誌寫入 | 數據同步、計數器更新 |
| 觸發器 | 不觸發 BEFORE/AFTER INSERT | 觸發 BEFORE INSERT/UPDATE, AFTER INSERT/UPDATE |
INSERT INTO menus (id,label,url) VALUES (4,'New Label','new.html')
ON DUPLICATE KEY UPDATE
label=VALUES(label),
url=VALUES(url),
update_time=NOW();
避免重複書寫值,維護性更強。
-- 方案 A:全量覆蓋同步
INSERT INTO target_table (id, col1, col2)
SELECT id, col1, col2 FROM source_table
ON DUPLICATE KEY UPDATE col1=VALUES(col1), col2=VALUES(col2);
-- 方案 B:增量同步(僅更新變更行)
INSERT INTO target_table (id, col1, col2, updated_at)
SELECT id, col1, col2, NOW() FROM source_table
WHERE updated_at > '2024-01-01'
ON DUPLICATE KEY UPDATE
col1=VALUES(col1),
col2=VALUES(col2),
updated_at=VALUES(updated_at);
ON DUPLICATE KEY UPDATE 在 Row 模式下正確複製,Statement 模式需注意核心選擇:**業務要求「以新為準」用 ON DUPLICATE KEY UPDATE,「以舊為準/去重」用 INSERT IGNORE**。兩者配合批量操作,優雅解決 99% 的唯一鍵衝突場景。