REPLACE INTO table_name (col1, col2, ...) VALUES (val1, val2, ...); -- 或 REPLACE INTO table_name (col1, col2, ...) SELECT ...; -- 或 REPLACE INTO table_name SET col1=val1, col2=val2, ...;
關鍵前提: 表**必須有主鍵或唯一索引**。否則
REPLACE INTO退化為純INSERT,導致重複數據。
ON DELETE 觸發器、外鍵級聯)。INSERT ... ON DUPLICATE KEY UPDATE (IODKU)| 特性 | REPLACE INTO | INSERT ... ON DUPLICATE KEY UPDATE |
|---|---|---|
| 語義 | 刪除舊行 + 插入新行 | 原地更新現有行 |
| 自增 ID | **改變** (重新分配) | **保持不變** |
| 觸發器 | 觸發 DELETE + INSERT | 觸發 UPDATE |
| 外鍵級聯 | 觸發級聯刪除/插入 (危險!) | 不觸發級聯 |
| 性能 | 較慢 (雙重操作 + 索引維護) | 較快 (單次索引查找 + 就地更新) |
| 適用場景 | 需完全替換行、無外鍵依賴、不介意 ID 變化 | **絕大多數業務場景首選** |
CREATE TABLE user_last_login (
user_id BIGINT UNSIGNED PRIMARY KEY,
last_login_time DATETIME NOT NULL,
login_count INT UNSIGNED DEFAULT 0,
UNIQUE KEY uk_user (user_id)
);
-- 方案 A: REPLACE INTO (會重置 login_count 為 0,除非顯式帶上)
REPLACE INTO user_last_login (user_id, last_login_time)
VALUES (1001, NOW());
-- 結果:login_count 變為 0 (默認值),user_id 同但內部行 ID 可能變
-- 方案 B: IODKU (推薦,保留原有列值,原子累加)
INSERT INTO user_last_login (user_id, last_login_time, login_count)
VALUES (1001, NOW(), 1)
ON DUPLICATE KEY UPDATE
last_login_time = VALUES(last_login_time),
login_count = login_count + 1;
-- 結果:last_login_time 更新,login_count 遞增,主鍵 ID 不變
REPLACE INTO users (id, name, email, updated_at) VALUES (1, '張三', 'zhangsan@example.com', NOW());
REPLACE INTO settings SET
`key` = 'site_title',
`value` = '我的博客',
updated_at = NOW();
ON DELETE CASCADE/SET NULL,導致關聯數據誤刪/誤改。REPLACE 導致自增 ID 快速耗盡或碎片化。VALUES 中指定的列會被重置為默認值,而非保留舊值。INSERT 和 DELETE 權限。90% 以上場景請使用
INSERT ... ON DUPLICATE KEY UPDATE。
僅在以下極少數情況考慮REPLACE INTO:
① 需要物理上完全替換行(如表結構變更後的數據遷移)。
② 表無外鍵、無觸發器、業務不依賴自增 ID、且確確實實想「刪舊插新」。
③ 兼容極老版本 MySQL (3.22 前) 不支持 IODKU 的場景(現已絕跡)。