REPLACE
导学
当你需要"存在则更新,不存在则插入"时,通常要写 SELECT 判断 + UPDATE 或 INSERT 两条语句。REPLACE 提供了一种更简洁的替代方案——它先尝试删除旧记录,再插入新记录,从而实现"覆盖式"写入。
定义
REPLACE:DML 语句,用于插入数据,如果表中已存在相同主键或唯一键的记录,则先删除旧记录,再插入新记录。如果记录不存在,则直接插入。
核心语法
-- 与 INSERT 语法完全一致
REPLACE INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...);
-- 支持 INSERT 的所有变体
REPLACE INTO 表名 SET 列1 = 值1, 列2 = 值2;
REPLACE INTO 表名 SELECT ... FROM 其他表;
演示数据准备
DROP TABLE IF EXISTS employees;
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
emp_name VARCHAR(20),
dept VARCHAR(20),
score DECIMAL(5,2)
);
INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);
当前 employees 表中的完整数据如下:
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
SQL 示例
场景一:主键冲突时覆盖更新
当前数据状态:见上文 employees 表完整数据。
执行语句:
REPLACE INTO employees (emp_id, emp_name, dept, score)
VALUES (2, '白歌', '产品部', 88);
操作后结果:
SELECT * FROM employees;
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 产品部 | 88 |
结果解读:emp_id = 2 已存在(白歌),REPLACE 的执行过程是:
- 先删除
emp_id = 2的旧记录(技术部, NULL) - 再插入新记录(产品部, 88)
最终效果看起来像是"更新"了白歌的部门和分数,但实际上是先删后插。
注意:
AUTO_INCREMENT主键如果显式指定了值(如本例的emp_id = 2),则保持该值;如果省略主键让数据库自动生成,冲突删除后新插入的记录会获得新的自增值。
场景二:无冲突时直接插入
当前数据状态:见上文更新后的 employees 表。
执行语句:
REPLACE INTO employees (emp_id, emp_name, dept, score)
VALUES (3, '孔蓝', '运营部', 92);
操作后结果:
SELECT * FROM employees;
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 产品部 | 88 |
| 3 | 孔蓝 | 运营部 | 92 |
结果解读:emp_id = 3 不存在,因此 REPLACE 直接插入新记录,行为与 INSERT 完全一致。返回受影响行数为 1。
场景三:REPLACE 与 INSERT ... ON DUPLICATE KEY UPDATE 的对比
当前数据状态:重新初始化:
DELETE FROM employees WHERE emp_id = 3;
UPDATE employees SET dept = '技术部', score = NULL WHERE emp_id = 2;
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
执行语句(REPLACE):
REPLACE INTO employees (emp_id, emp_name, dept, score)
VALUES (2, '白歌', '产品部', 88);
执行语句(INSERT ... ON DUPLICATE KEY UPDATE):
INSERT INTO employees (emp_id, emp_name, dept, score)
VALUES (2, '白歌', '产品部', 88)
ON DUPLICATE KEY UPDATE dept = VALUES(dept), score = VALUES(score);
两种方式的最终表状态相同:
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 产品部 | 88 |
但内部机制差异很大:
| 特性 | REPLACE | INSERT ... ON DUPLICATE KEY UPDATE |
|---|---|---|
| 实现方式 | 先删除旧行,再插入新行 | 直接更新旧行的指定字段 |
| 触发器行为 | 触发 DELETE + INSERT 触发器 | 只触发 UPDATE 触发器 |
| 自增值变化 | 删除后重新插入,自增值可能变化 | 不删除,自增值不变 |
| 未指定字段 | 新记录中未指定的字段变为默认值 | 未指定的字段保持原值 |
| 性能 | 较差(两次操作) | 较好(单次更新) |
| 外键约束 | 删除可能触发级联删除 | 不触发级联删除 |
结果解读:
REPLACE是"暴力覆盖":旧记录完全消失,新记录重新生成INSERT ... ON DUPLICATE KEY UPDATE是"精准更新":只修改指定字段,保留其他字段原值- 生产环境优先使用
INSERT ... ON DUPLICATE KEY UPDATE,更安全、性能更好
场景四:REPLACE 的陷阱——未指定字段变默认值
当前数据状态:重新初始化:
UPDATE employees SET dept = '技术部', score = NULL WHERE emp_id = 2;
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 技术部 | 100 |
| 2 | 白歌 | 技术部 | NULL |
执行语句:
REPLACE INTO employees (emp_id, emp_name, dept)
VALUES (1, '大翔', '产品部');
操作后结果:
SELECT * FROM employees;
| emp_id | emp_name | dept | score |
|---|---|---|---|
| 1 | 大翔 | 产品部 | NULL |
| 2 | 白歌 | 技术部 | NULL |
结果解读:REPLACE 只指定了 emp_id、emp_name、dept,没有指定 score。由于 REPLACE 是先删除再插入,新插入的记录中未指定的 score 会变为默认值(本例中 score 没有 DEFAULT,因此为 NULL)。大翔原来的 score = 100 被"意外"丢失了!
这是 REPLACE 最常见的陷阱。相比之下,INSERT ... ON DUPLICATE KEY UPDATE 只更新指定字段,不会丢失未提及的字段值。
常见误区
| 误区 | 正解 |
|---|---|
"REPLACE 和 UPDATE 一样只修改指定字段" | 不是。REPLACE 是先删除旧记录再插入新记录,未指定的字段会丢失或变默认值。 |
"REPLACE 比 INSERT ... ON DUPLICATE KEY UPDATE 更好" | 恰恰相反。生产环境优先用 INSERT ... ON DUPLICATE KEY UPDATE,性能更好且不会丢失字段。 |
"REPLACE 不会触发触发器" | 会触发。REPLACE 触发 DELETE 触发器(旧记录)+ INSERT 触发器(新记录)。 |
"REPLACE 的自增值不变" | 会变。旧记录删除后,新插入的记录如果由数据库生成自增值,会得到新值。 |
"REPLACE 可以用于没有主键/唯一键的表" | 不能。没有冲突检测依据时,REPLACE 行为等同于 INSERT。 |
面试考点
Q:REPLACE 和 INSERT ... ON DUPLICATE KEY UPDATE 的区别?
REPLACE是先删除旧记录再插入新记录,会丢失未指定字段的值,触发 DELETE + INSERT 触发器,自增值可能变化;2.INSERT ... ON DUPLICATE KEY UPDATE是直接更新旧记录的指定字段,保留其他字段原值,只触发 UPDATE 触发器,自增值不变。生产环境优先用后者。
Q:REPLACE 的适用场景是什么?
适合简单场景:全量覆盖写入,不关心旧记录的其他字段值。例如:定时全量同步外部数据源,每次同步直接用
REPLACE覆盖。但大多数业务场景更适合INSERT ... ON DUPLICATE KEY UPDATE。
Q:REPLACE 对自增主键的影响?
如果显式指定主键值(如
REPLACE INTO t (id, ...) VALUES (5, ...)),则保持该值;如果省略主键让数据库自动生成,删除旧记录后新插入的记录会获得新的自增值(旧值不会复用)。这可能导致自增值跳跃增长。
Q:为什么生产环境不推荐 REPLACE?
- 先删后插的性能开销大于直接更新;2. 未指定字段会丢失或变默认值,容易误删数据;3. 触发器行为复杂(DELETE + INSERT 两次触发);4. 有外键时,删除可能触发级联删除,导致关联数据意外丢失。
小结
REPLACE实现"存在则覆盖,不存在则插入",但内部是先删除再插入- 未指定的字段会丢失或变为默认值,这是最常见的陷阱
- 生产环境优先使用
INSERT ... ON DUPLICATE KEY UPDATE,更安全高效 REPLACE会触发 DELETE + INSERT 两次触发器,自增值可能变化- 有外键约束的表慎用
REPLACE,避免级联删除风险
下一章引子:学会了增删改查四大操作,接下来深入了解 MySQL 中各种数据类型的特性和选型原则。