带delete子句的MERGE配合触发器为何触发ORA-30926错误?
问题复现准备
准备用于复现问题的schema如下:
create table t (id int, val int, modified timestamp default systimestamp) / create or replace trigger trigg_on_t before update on t for each row enable begin :new.modified := systimestamp; end; / insert into t (id, val) values (1, 1); commit;
报错触发场景
当目标表上定义了上述BEFORE UPDATE行级触发器时,执行带DELETE子句的MERGE语句会触发错误,测试SQL如下:
merge into t using ( select 1 id, 10 val, 1 flag from dual ) s on (t.id = s.id) when matched then update set t.val=s.val delete where s.flag=1
执行后返回报错:
ORA-30926: unable to get a stable set of rows in the source tables
30926, 00000, "unable to get a stable set of rows in the source tables"
// *原因:大量DML操作或非确定性where子句导致无法获取稳定的源表行集
// *解决方案:移除所有非确定性where子句后重新执行DML。
核心疑问:
该场景下的执行逻辑存在什么问题?报错提示中提到的非确定性where子句究竟出现在哪里?
对照验证结果
经测试,以下两种操作都可以让上述MERGE语句正常执行,不会触发报错:
-- 方式1:在update子句中显式设置timestamp字段取值 merge into t using ( select 1 id, 1 val, 1 flag from dual ) s on (t.id = s.id) when matched then update set t.val=s.val, modified=systimestamp delete where s.flag=1 / -- 执行结果:1 row merged. rollback; -- 方式2:禁用表上的触发器 alter trigger trigg_on_t disable; merge into t using ( select 1 id, 1 val, 1 flag from dual ) s on (t.id = s.id) when matched then update set t.val=s.val delete where s.flag=1 / -- 执行结果:1 row merged.
根因说明
这个场景下不存在用户手写的非确定性WHERE子句,报错本质是触发器的副作用触发了Oracle的MERGE行集稳定性校验:
- 带DELETE子句的MERGE执行逻辑中,Oracle完成MATCHED分支的UPDATE操作后,会重新读取被更新的目标行,校验该行是否满足DELETE的过滤条件。
- 测试用的BEFORE UPDATE行级触发器,会在每次更新行时调用systimestamp给modified字段赋值——systimestamp是随调用时间变化的非确定性函数,触发器的修改不属于MERGE语句本身声明的字段更新逻辑,Oracle在重流行做DELETE校验时,会检测到同一行的modified字段取值和UPDATE执行阶段的计算结果不一致,判定目标行集不稳定,最终抛出ORA-30926错误。
- 两种规避方案生效的原因也很明确:
- 显式在UPDATE子句中设置modified字段取值时,Oracle将该字段的修改纳入MERGE本身的执行逻辑,不会判定为预期外的行值变动
- 禁用触发器后,不存在额外的行值修改逻辑,行集稳定性校验自然可以通过
内容的提问来源于stack exchange,提问作者0xdb
相关产品推荐
相关产品推荐

