mysql不支持标准merge语句,innodb引擎下需用insert … on duplicate key update实现“存在则更新、不存在则插入”,该语法要求表有主键或唯一索引,冲突时执行原子更新,避免分步操作的并发与性能问题。

MySQL不支持MERGE,得换语法
MySQL 8.0 之前完全没 MERGE 语句;8.0 虽然加了 MERGE,但只在 NDB Cluster 引擎里可用,InnoDB 仍不支持。所以日常用 InnoDB 的人,别在 MySQL 里找 MERGE——它根本不会执行,会直接报错 ERROR 1064 (42000)。
实际要实现“存在则更新、不存在则插入”,得用 INSERT ... ON DUPLICATE KEY UPDATE 或 REPLACE INTO(后者有隐式删除风险)。
-
INSERT ... ON DUPLICATE KEY UPDATE要求表有PRIMARY KEY或UNIQUE约束,否则无法判断“重复” - 更新字段时不能写
SET col = col + 1这类表达式后还带VALUES(col),容易误覆盖——正确写法是col = col + 1或col = VALUES(col) + 1 -
REPLACE INTO本质是先DELETE再INSERT,会触发两次自增 ID、丢失触发器中的OLD行数据、破坏外键级联行为
PostgreSQL用INSERT ... ON CONFLICT实现等效MERGE
PostgreSQL 没 MERGE 关键字,但 INSERT ... ON CONFLICT 是标准且稳定的替代方案,从 9.5 就支持,语义更清晰、控制更细。
关键点在于 ON CONFLICT 后必须指定冲突目标:要么是索引名(ON CONFLICT ON CONSTRAINT xxx),要么是列组合(ON CONFLICT (a, b)),不能只写 ON CONFLICT 不带目标,否则报错 ERROR: ON CONFLICT requires a conflict target。
- 如果用
DO NOTHING,冲突时整条跳过,不报错也不更新 - 用
DO UPDATE SET时,EXCLUDED是个伪表,代表本次想插入但被拦下的那行数据,比如SET name = EXCLUDED.name - 注意
WHERE子句可加在DO UPDATE后,用于限制更新条件,例如只更新非空值:WHERE EXCLUDED.status IS NOT NULL
SQL Server和Oracle真有MERGE,但语法差异大
SQL Server 和 Oracle 都原生支持 MERGE,但写法不兼容,迁代码时容易翻车。
SQL Server 的 MERGE 必须以 USING 子句引入源数据(可以是表、CTE 或 VALUES),且 WHEN MATCHED 和 WHEN NOT MATCHED 后必须跟 THEN,漏掉会语法错误;另外,MATCHED 分支默认对所有匹配行执行,如需加条件得写 WHEN MATCHED AND condition THEN ...。
Oracle 的 MERGE 对 USING 要求宽松些,但 ON 条件里不能出现聚合函数或子查询,否则报 ORA-00934: group function is not allowed here。
- SQL Server 中,
MERGE语句末尾必须加分号;,否则可能和下一条语句合并执行出错 - Oracle 中,
UPDATE和INSERT子句里的列名不能加表别名前缀(比如不能写t.col = ...),否则报ORA-00904: invalid identifier - 两个平台都不允许在
MERGE的ON条件里修改目标表字段,否则触发mutating table类错误
用MERGE还是分步操作?看事务和性能边界
表面上 MERGE 或其等效语法更简洁,但真实场景中是否该用,取决于数据量、并发压力和错误容忍度。
小批量单行操作(比如用户资料保存),用 INSERT ... ON DUPLICATE KEY UPDATE 或 ON CONFLICT 完全没问题;但如果是批量导入几万行,又要求部分失败不影响整体,就得小心——PostgreSQL 的 ON CONFLICT 支持逐行处理,而 SQL Server 的 MERGE 是原子性语句,一行错就全滚回。
- 高并发写同一主键时,
MERGE类操作可能引发间隙锁争用,MySQL 在 RR 隔离级别下尤其明显 - 某些 ORM(如 Django ORM)不原生生成
MERGE或ON CONFLICT,硬塞进去容易绕过连接池或事务管理 - 日志和审计系统里,
MERGE的“一次操作两种语义”会让变更记录难追溯——到底是插进来的,还是更新来的,得靠额外字段标记
真正难的不是语法怎么写,而是想清楚:你到底需要“原子性优先”,还是“容错性优先”,以及下游系统能不能消化这种混合行为。










