INSERT INTO `table` (col1, col2, ...)
VALUES (v11, v12, ...), (v21, v22, ...), ...
ON DUPLICATE KEY UPDATE
col2 = VALUES(col2),
col3 = VALUES(col3);
UNIQUE 或 PRIMARY KEY 衝突 → 執行 UPDATE在 ON DUPLICATE KEY UPDATE 子句中,VALUES(col_name) 可引用 VALUES 列表中對應欄位的當前行值,實現「以插入值更新舊行」。
假設表 stats:
CREATE TABLE `stats` (
`id` INT PRIMARY KEY,
`counter` INT NOT NULL DEFAULT 0,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
初始資料:
INSERT INTO `stats` (`id`, `counter`) VALUES (1, 10), (2, 20);
INSERT INTO `stats` (`id`, `counter`)
VALUES (1, 5), (2, 3), (3, 100)
ON DUPLICATE KEY UPDATE
`counter` = `counter` + VALUES(`counter`),
`updated_at` = CURRENT_TIMESTAMP;
執行結果:
INSERT INTO `t` (`k`, `v`) VALUES ('a', 10), ('b', 20)
ON DUPLICATE KEY UPDATE
`v` = IF(VALUES(`v`) > `v`, VALUES(`v`), `v`); -- 只更新較大值
INSERT INTO `users` (`email`, `name`, `login_count`, `last_login`)
VALUES ('a@b.com', 'Alice', 1, NOW()),
('c@d.com', 'Bob', 1, NOW())
ON DUPLICATE KEY UPDATE
`login_count` = `login_count` + VALUES(`login_count`),
`last_login` = VALUES(`last_login`);
-- name 欄位不在 UPDATE 列表,保持原值
INSERT INTO `logs` (`msg`) VALUES ('msg1'), ('msg2')
ON DUPLICATE KEY UPDATE `id` = LAST_INSERT_ID(`id`);
SELECT LAST_INSERT_ID(); -- 返回第一行衝突/插入的 ID
ON CONFLICT,SQL Server 用 MERGE)UPDATE 時,BEFORE INSERT/AFTER INSERT 觸發器不會再次觸發,但 BEFORE UPDATE/AFTER UPDATE 會觸發AUTO_INCREMENT 計數器在衝突更新時不會遞增max_allowed_packet) 或鎖定過久PRIMARY KEY 或 UNIQUE INDEX,否則永不觸發更新LOAD DATA INFILE + 暫存表 處理超大量匯入,再合併