【故障记录】Merge的数据重复问题 ORA-30926 无法在源表中获得一组稳定的行

问题描述


今天跑批过程报错了,查看了日志,报错代码为:ORA-30926: 无法在源表中获得一组稳定的行,发现是使用merge更新数据导致的。


在这里插入图片描述

为了解决这个问题,得先弄明白merge的逻辑。merge into是insert与update语句的结合,可以同时实现update和insert的功能,语法大致如下

merge into 目标表 a
using (
源表
) b
on (源表与目标表的关联条件) --关联字段用目标表的主键
when matched then update --当源表通过关联字段能匹配到目标表时,执行更新操作
set 用源表字段值更新目标表字段值
when not matched then insert --当源表通过关联字段不能匹配到目标表时,执行插入操作
(
目标表字段
)
values
(
源表对应的字段
)
;
commit;

merge into会将源表的每一条记录和目标表按关联字段匹配,目标表被匹配到的记录会更新数据,匹配不到的记录话就会把源表这些数据插入目标表,匹配的前提是关联字段要是目标表与源表的主键。

所以,如果源表的关联字段有重复值的话,程序就不知道该选择哪条去更新目标表,因此就会抛出如上所述之错误。为了解决这个问题,我们先来复现一下这个错误。

--drop table merge_target_test;
--创建目标表
create table merge_target_test(
    D_DATA_DT date --数据日期
   ,V_TRADE_NO varchar2(10) --交易编号
   ,V_SEC_NO varchar2(10) --证券代码
   ,N_PV numeric(24,6) --估值结果
);

--drop table merge_source_test;
--创建源表
create table merge_source_test(
    D_DATA_DT date --数据日期
   ,V_TRADE_NO varchar2(10) --交易编号
   ,V_SEC_NO varchar2(10) --证券代码
   ,N_PV numeric(24,6) --估值结果
);

--目标表插入一条数据
insert into merge_target_test(D_DATA_DT,V_TRADE_NO,V_SEC_NO,N_PV)
values(TO_DATE('20210101', 'YYYY-MM-DD'),'No_Test01','000905.SH',100.00);commit;

--目标表插入两条交易编号一样的数据(制造关联字段主键重复)
insert into merge_source_test(D_DATA_DT,V_TRADE_NO,V_SEC_NO,N_PV)
values(TO_DATE('20210101', 'YYYY-MM-DD'),'No_Test01','000905.SH',200.00);commit;

insert into merge_source_test(D_DATA_DT,V_TRADE_NO,V_SEC_NO,N_PV)
values(TO_DATE('20210101', 'YYYY-MM-DD'),'No_Test01','000905.SH',300.00);commit;

--执行merge操作
merge into merge_target_test a
using (
    select *
    from merge_source_test
) b
on (a.d_data_dt=b.d_data_dt and a.v_trade_no = b.v_trade_no) --关联字段用目标表的主键
when matched then update
set --更新字段值(注释掉关联字段)
 --a.D_DATA_DT      = b.D_DATA_DT
--,a.V_TRADE_NO     = b.V_TRADE_NO
   a.V_SEC_NO       = b.V_SEC_NO
  ,a.N_PV           = b.N_PV
when not matched then insert
(
 	 a.D_DATA_DT
  ,a.V_TRADE_NO
  ,a.V_SEC_NO
  ,a.N_PV
)
values
(
   b.D_DATA_DT
  ,b.V_TRADE_NO
  ,b.V_SEC_NO
  ,b.N_PV
)
;
commit;

执行完上面merge代码就会抛出ORA-30926错误。


解决方案


这个问题解决办法是删除源表里面主键重复的数据,或者对于关联字段重新给一组主键,以使源表数据按主键字段不会出现重复即可。

如下代码可以正常执行,并且更新了目标表已有数据,插入了没有的数据。

--清空目标表与源表
truncate table merge_target_test;
truncate table merge_source_test;

--目标表插入一条数据
insert into merge_target_test(D_DATA_DT,V_TRADE_NO,V_SEC_NO,N_PV)
values(TO_DATE('20210101', 'YYYY-MM-DD'),'No_Test01','000905.SH',100.00);commit;

--目标表插入交易编号不重复
insert into merge_source_test(D_DATA_DT,V_TRADE_NO,V_SEC_NO,N_PV)
values(TO_DATE('20210101', 'YYYY-MM-DD'),'No_Test01','000905.SH',200.00);commit;

insert into merge_source_test(D_DATA_DT,V_TRADE_NO,V_SEC_NO,N_PV)
values(TO_DATE('20210101', 'YYYY-MM-DD'),'No_Test02','000905.SH',300.00);commit;

--执行merge操作
merge into merge_target_test a
using (
    select *
    from merge_source_test
) b
on (a.d_data_dt=b.d_data_dt and a.v_trade_no = b.v_trade_no) --关联字段用目标表的主键
when matched then update
set --更新字段值(注释掉关联字段)
 --a.D_DATA_DT      = b.D_DATA_DT
--,a.V_TRADE_NO     = b.V_TRADE_NO
   a.V_SEC_NO       = b.V_SEC_NO
  ,a.N_PV           = b.N_PV
when not matched then insert
(
 	 a.D_DATA_DT
  ,a.V_TRADE_NO
  ,a.V_SEC_NO
  ,a.N_PV
)
values
(
   b.D_DATA_DT
  ,b.V_TRADE_NO
  ,b.V_SEC_NO
  ,b.N_PV
)
;
commit;

你可能感兴趣的:(数据库,code,brain,damage,数据库)