执行Oracle MERGE语句报ORA-00905缺失关键字错误如何解决
报错触发原因
你用到的WHEN NOT MATCHED BY OLD_R、WHEN NOT MATCHED BY NEW_R属于SQL Server的MERGE语法扩展,Oracle官方并未支持该用法,Oracle的MERGE语法中WHEN NOT MATCHED后不允许跟BY关键字,语法解析器遇到未预期的BY关键字后无法找到符合规则的后续关键字,因此抛出ORA-00905缺失关键字错误。
此外你原SQL中INSERT子句写了目标表别名前缀OLD_R.,也不符合Oracle MERGE语法要求,MERGE INTO已经指定了目标表,INSERT字段无需再加别名前缀。
修复方案
基础修复(仅实现更新、插入逻辑,解决语法报错)
直接调整语法符合Oracle规则即可,修改后SQL如下:
MERGE INTO INTERVIEW OLD_R USING NEW_INTERVIEW NEW_R ON (NEW_R.REG_NO = OLD_R.REG_NO) WHEN MATCHED AND (NEW_R.NAME <> OLD_R.NAME OR NEW_R.MOB_NO <> OLD_R.MOB_NO) THEN UPDATE SET OLD_R.NAME = NEW_R.NAME, OLD_R.MOB_NO = NEW_R.MOB_NO WHEN NOT MATCHED THEN INSERT(NAME, REG_NO, MOB_NO) VALUES(NEW_R.NAME, NEW_R.REG_NO, NEW_R.MOB_NO);
完整同步修复(保留删除源表不存在的目标行逻辑)
如果需要实现目标表和源表完全同步(匹配更新、不存在插入、源无则删),Oracle没有直接的对应语法,有两种常用实现方案:
- 方案1:先执行MERGE更新插入,再单独执行DELETE删除多余行
-- 第一步:执行更新插入 MERGE INTO INTERVIEW OLD_R USING NEW_INTERVIEW NEW_R ON (NEW_R.REG_NO = OLD_R.REG_NO) WHEN MATCHED AND (NEW_R.NAME <> OLD_R.NAME OR NEW_R.MOB_NO <> OLD_R.MOB_NO) THEN UPDATE SET OLD_R.NAME = NEW_R.NAME, OLD_R.MOB_NO = NEW_R.MOB_NO WHEN NOT MATCHED THEN INSERT(NAME, REG_NO, MOB_NO) VALUES(NEW_R.NAME, NEW_R.REG_NO, NEW_R.MOB_NO); -- 第二步:删除目标表中源表不存在的行 DELETE FROM INTERVIEW OLD_R WHERE NOT EXISTS ( SELECT 1 FROM NEW_INTERVIEW NEW_R WHERE NEW_R.REG_NO = OLD_R.REG_NO );
- 方案2:改造MERGE的USING数据源为全外连接结果,单句完成全量同步
MERGE INTO INTERVIEW OLD_R USING ( SELECT COALESCE(N.REG_NO, O.REG_NO) AS REG_NO, N.NAME, N.MOB_NO, CASE WHEN N.REG_NO IS NULL THEN 1 ELSE 0 END AS IS_DELETE FROM NEW_INTERVIEW N FULL OUTER JOIN INTERVIEW O ON N.REG_NO = O.REG_NO ) NEW_R ON (NEW_R.REG_NO = OLD_R.REG_NO) WHEN MATCHED THEN UPDATE SET OLD_R.NAME = NEW_R.NAME, OLD_R.MOB_NO = NEW_R.MOB_NO DELETE WHERE NEW_R.IS_DELETE = 1 WHEN NOT MATCHED THEN INSERT(NAME, REG_NO, MOB_NO) VALUES(NEW_R.NAME, NEW_R.REG_NO, NEW_R.MOB_NO);
ORA-00905通用排查思路
- 优先检查是否混用了其他数据库的专属语法,不同数据库的SQL扩展语法差异较大,不能直接复用
- 逐行核对对应数据库官方语法文档,确认关键字拼写、顺序、配套用法是否正确
- 复杂SQL可以逐段注释后执行,快速定位报错的具体代码段
内容的提问来源于stack exchange,提问作者Surya Magesh
相关产品推荐
相关产品推荐

