根本原因是源表ON字段存在重复值,导致一对多匹配,数据库无法确定唯一更新源行,从而在校验阶段抛出ORA-30926错误。
MERGE语句报ORA-30926或类似错误,根本原因不是语法写错了,而是源表中用于ON条件的字段存在重复值,导致一个目标行被多个源行同时匹配——数据库拒绝执行这种模糊决策。
数据库执行MERGE时,第一阶段必须为每个目标行确定唯一对应的源行。一旦源表中ON子句所用字段(比如order_id、customer_code)出现重复,就形成一对多映射。此时引擎无法判断该用哪条源记录更新目标行,立刻抛出类似ORA-30926或Cannot obtain a stable set of rows的错误。
transaction_id
NULL视为相等,也会触发该错误The MERGE statement attempted to UPDATE or DELETE the same row more than once
MySQL没有MERGE关键字,常用INSERT ... ON DUPLICATE KEY UPDATE模拟。但它只按主键/唯一键冲突触发更新,不校验源数据是否重复——表面成功,实际可能用最后一条重复记录覆盖前面的正确值,造成静默数据污染。
INSERT ... ON CONFLICT,同样跳过源端去重检查UPDATE+INSERT+DELETE,但要额外加NOT EXISTS或临时表去重merge sql error,大概率是误写了MERGE关键字而非适配MySQL语法有人试图在目标表加唯一索引,指望数据库在INSERT时报错再回滚——这完全无效。MERGE的“稳定行”校验发生在DML执行前,约束冲突根本不会触发。
ROW_NUMBER() OVER (PARTITION BY join_key ORDER BY ...)标记重复,并只取rn = 1的行ON t.target_col = s.source_col::numeric(10,2)
真正棘手的不是怎么写MERGE,而是怎么证明源数据在关联键上确实无重复——这往往要追溯到上游ETL清洗逻辑,或者API调用方的数据生成规则。一旦漏掉这个验证环节,再漂亮的MERGE语句也只是定时炸弹。