「若記錄存在則更新,否則插入」(Upsert)。常見於:計數器增量、用戶設定寫入、日誌去重寫入。
INSERT INTO table (cols) VALUES (...)
ON DUPLICATE KEY UPDATE col1=VALUES(col1), col2=VALUES(col2), ...;
VALUES(col) 取得 VALUES 子句中該欄位的輸入值。CREATE TABLE spk_goods (
gid INT AUTO_INCREMENT PRIMARY KEY,
cid INT NOT NULL COMMENT '分類',
name CHAR(30) NOT NULL COMMENT '貨物名稱',
UNIQUE KEY uk_name (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
gid | cid | name
----|-----|-----
1 | 1 | apple
2 | 2 | banana
INSERT INTO spk_goods (cid, name) VALUES (1, 'apple')
ON DUPLICATE KEY UPDATE name = CONCAT(name, 'new');
結果:apple → applenew,gid=1 不變。
INSERT INTO spk_goods (cid, name) VALUES (2, 'watermelon')
ON DUPLICATE KEY UPDATE name = CONCAT(name, 'new');
結果:新增 gid=3, cid=2, name='watermelon'。
INSERT INTO t (a,b,c) VALUES
(1,2,3), (2,5,7), (3,3,6), (4,8,2)
ON DUPLICATE KEY UPDATE b=VALUES(b);
a 為 UNIQUE,原有 (2,2,9)、(3,2,1)。(2,5,9)、(3,3,1) 更新;(1,2,3)、(4,8,2) 新增。LAST_INSERT_ID() 取得自增 IDINSERT INTO t (id, val) VALUES (NULL, 'x')
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), val='x';
SELECT LAST_INSERT_ID(); -- 返回新增或更新行的自增 ID
INSERT INTO t (k, v) VALUES ('key', 100)
ON DUPLICATE KEY UPDATE v = IF(VALUES(v) > v, VALUES(v), v); -- 只增不減
ER_LOCK_DEADLOCK 重試。BEFORE INSERT 與 BEFORE UPDATE 皆會觸發。binlog_format=ROW)。| 特性 | ON DUPLICATE KEY UPDATE | REPLACE INTO |
|---|---|---|
| 操作本質 | 更新現有行 | DELETE + INSERT |
| 自增 ID | 保持不變 | 重新分配 |
| 外鍵關聯 | 保留 | 斷開(舊行刪除) |
| 觸發器 | UPDATE 類 | DELETE + INSERT 類 |