mysql不支持merge语句,自8.0.20起仍报error 1064;必须用insert ... on duplicate key update替代,且依赖唯一索引触发更新逻辑。

MySQL 不支持 MERGE,别硬套语法
MySQL 从 8.0.20 开始仍不支持标准 SQL 的 MERGE 语句。如果你在 MySQL 里直接写 MERGE INTO ... USING ...,会报错 ERROR 1064 (42000)。这不是语法写错了,是引擎压根没实现。PostgreSQL、SQL Server、Oracle 支持,但 MySQL 用户得换思路。
MySQL 替代方案:用 INSERT ... ON DUPLICATE KEY UPDATE
这是最常用、最稳妥的同步方式,前提是目标表有唯一索引(UNIQUE 或主键),否则无法触发“重复时更新”逻辑。
-
INSERT语句必须包含所有ON DUPLICATE KEY UPDATE中要更新的列,且这些列需能命中唯一约束 - 源表字段名和目标表字段名不一致时,要用
AS别名或显式写出字段映射,例如:SELECT src.id AS target_id, src.name FROM source_table src - 不能在
UPDATE子句里引用未出现在INSERT列表中的源字段;如果想用子查询计算值,得包在VALUES()或SELECT中 - 性能上,只要索引有效,单次执行几千行效率不错;超万行建议分批,避免锁表太久
INSERT INTO target_table (id, name, status) SELECT id, name, 'active' FROM source_table ON DUPLICATE KEY UPDATE name = VALUES(name), status = VALUES(status);
PostgreSQL / SQL Server 用 MERGE 要注意匹配条件和动作顺序
MERGE 不是“先查再改”,而是基于 ON 条件一次性匹配,然后按 WHEN MATCHED / WHEN NOT MATCHED 分支执行。容易出错的点集中在:
-
ON子句里不能用目标表的非索引字段做模糊匹配(如ON t.name ~ s.pattern),会导致全表扫描甚至死锁 - 多个
WHEN MATCHED分支时,SQL Server 要求它们互斥(用AND加条件),而 PostgreSQL 要求按顺序匹配,第一个成立就执行,后面的跳过 - 如果源数据里同一
ON键出现多次,SQL Server 会报错The MERGE statement attempted to update or delete the same row more than once;PG 默认允许,但结果不可控,应提前去重
跨库或异构同步时,MERGE 通常不是第一选择
比如从 MySQL 同步到 PostgreSQL,或者从 CSV 文件导入并更新目标表——这类场景下,MERGE 往往难直接用。更实际的做法是:
- 先把源数据载入临时表(
CREATE TEMP TABLE或pg_tempschema),再用INSERT ... ON CONFLICT(PG)或INSERT ... ON DUPLICATE KEY UPDATE(MySQL)操作主表 - 避免在
MERGE的USING子句里写复杂 JOIN 或子查询,尤其涉及大表时,计划器可能选错执行路径,导致慢得离谱 - 如果源数据来自外部 API 或文件,优先考虑用程序控制批次+事务,比拼一个巨型
MERGE更易调试、回滚和监控
真正麻烦的从来不是语法,而是“哪些行该更新、哪些该插入、哪些该忽略”的业务逻辑边界。写之前,先用 SELECT 模拟匹配结果,比直接跑 MERGE 安全得多。










