merge不支持同一when matched子句中同时update和delete,必须拆分为互斥的when matched and条件分支;delete只能在matched中基于源数据标记触发,不可用not matched by source替代逻辑删除。

MERGE 本身不支持在同一个 WHEN MATCHED 子句里既 UPDATE 又 DELETE;必须拆成两个独立的匹配分支,且需用条件精确区分行为。
WHEN MATCHED 必须用 AND 分条件,不能写多个无约束的 MATCHED
SQL Server 要求每个 MATCHED 分支有互斥逻辑,否则报错 The MERGE statement attempted to UPDATE or DELETE the same row more than once。常见错误是漏掉 AND 条件,导致同一行被多个 WHEN MATCHED 同时命中。
- 正确写法:一个
WHEN MATCHED AND target.status = 'inactive'做DELETE,另一个WHEN MATCHED AND target.status != 'inactive'做UPDATE - 错误写法:
WHEN MATCHED THEN UPDATE ...和WHEN MATCHED THEN DELETE并列,无AND区分 - 条件必须覆盖所有可能的匹配情况,否则未匹配上的行会被忽略(不是 bug,是设计)
DELETE 操作只能在 WHEN MATCHED 中触发,不能用 WHEN NOT MATCHED BY SOURCE
WHEN NOT MATCHED BY SOURCE 看似适合删旧数据,但它只对源表中“完全没出现”的目标行生效——而你要删的是“源表有、但标记为应删除”的行,这类行仍属于 MATCHED 范畴。
- 典型场景:同步用户表,源数据带
is_deleted = 1字段 → 必须在WHEN MATCHED AND source.is_deleted = 1下执行DELETE -
WHEN NOT MATCHED BY SOURCE适合清理“源端已彻底下线、连主键都不再存在”的残留数据,和业务逻辑删除不是一回事 - 如果误用
NOT MATCHED BY SOURCE做逻辑删除,会导致本该保留的活跃行被误删
UPDATE 和 DELETE 的执行顺序不可控,避免字段依赖冲突
SQL Server 不保证两个 WHEN MATCHED 分支的执行先后;若 UPDATE 和 DELETE 共享判断条件(比如都看 last_modified),可能因并发或优化器选择导致行为不一致。
- 推荐用稳定、不可变的字段做分支依据,例如
status、is_active、delete_flag等业务语义明确的列 - 避免用
UPDATE后刚改的值去触发后续DELETE——MERGE 是单次扫描,UPDATE的新值在本次 MERGE 中不可被其他分支读到 - 测试时务必用含混合状态(部分更新、部分删除)的数据集,验证是否真能分离处理
最易被忽略的是:DELETE 分支一旦触发,整行从目标表消失,后续任何其它分支都不会再处理它;所以条件表达式必须在 MERGE 扫描那一刻就确定,不能依赖 UPDATE 后产生的中间状态。










