當 INSERT 遇到 UNIQUE 或 PRIMARY KEY 衝突,預設拋出 1062 Duplicate entry 錯誤。MySQL 提供三種語法分別對應「覆蓋」、「更新」、「忽略」三種業務語義,選擇正確方案能簡化應用層邏輯並提升效能。
CREATE TABLE test1 (id INT, name VARCHAR(5), type INT, PRIMARY KEY (id)); CREATE TABLE test2 (id INT, name VARCHAR(5), type INT, PRIMARY KEY (id)); INSERT INTO test1 VALUES (101,'aaa',1),(102,'bbb',2),(103,'ccc',3); INSERT INTO test2 VALUES (201,'aaa',1),(202,'bbb',2),(203,'ccc',3),(101,'xxx',5);
test1 3 筆,test2 4 筆,id=101 為衝突鍵。
REPLACE INTO test1 (id, name) SELECT id, name FROM test2;
結果:
id=101 原行被刪除,新行 (101, 'xxx', NULL) 插入(type 未指定變 NULL)。201,202,203 正常插入,type 同樣為 NULL。完整欄位版:
REPLACE INTO test1 (id, name, type) SELECT id, name, type FROM test2;
此時 type 保留來源值,id=101 變為 (101, 'xxx', 5)。
特性總結:
DELETE + INSERT,觸發 BEFORE DELETE、AFTER DELETE、BEFORE INSERT、AFTER INSERT 觸發器。NULL。INSERT INTO test1 (id, name, type) SELECT id, name, type FROM test2 ON DUPLICATE KEY UPDATE test1.name = test2.name;
結果:
id=101 原行保留,name 更新為 'xxx',type 維持原值 1(未在 UPDATE 列表中)。特性總結:
VALUES(col) 參考插入值:UPDATE type = VALUES(type)。LAST_INSERT_ID() 回傳衝突行的主鍵值(MySQL 5.1+)。INSERT IGNORE INTO test1 (id, name, type) SELECT id, name, type FROM test2;
結果:
id=101 衝突,略過不處理,保留原行 (101, 'aaa', 1)。Query OK, 3 rows affected(僅計入成功插入行數)。特性總結:
| 業務需求 | 推薦方案 | 關鍵行為 |
|---|---|---|
| 以新資料完全取代舊資料(含所有欄位) | REPLACE INTO (全欄位) | DELETE + INSERT,觸發器全觸發,自增ID重算 |
| 保留舊資料部分欄位,僅同步特定欄位 | ON DUPLICATE KEY UPDATE | 就地UPDATE,保留未指定欄位,效能最佳 |
| 只導入缺失資料,既有資料完全不動 | INSERT IGNORE | 靜默略過衝突,不觸發觸發器 |
VALUES() 函數簡化 UPDATE 寫法:UPDATE name=VALUES(name), type=VALUES(type)。request_id),配合 ON DUPLICATE KEY UPDATE 實現精確去重。Innodb_row_lock_waits、Innodb_row_lock_time 指標評估鎖壓力。