ORACLE数据库:如何修正测试环境在插入数据时,出现唯一性错误
--A
背景:撰写此文档,是为了处理这类错误,
--B
分析问题的产生原因:
1、 问题发生在客户使用Expdp/Impdp的方法,新建的数据库账号上。
2、 Expdp 时,先导出了序列对象,然后再导出使用这些序列的表。
3、 由于是在业务期间的操作,某些序列的信息被导出到DMP后,应用系统此时还在持续读取该序列值,作为对应表的主键值,插入到表中。之后,该表才被导出到DMP文件里。
4、 显然,此时表里的主键值,比保存在DMP文件里该序列的当前值,要大;故,当将此DMP文件的数据导入库后,使用序列的下一个值,将出现表的主键值重复的情况,就会报上述错误。
--C
显然,要消除此语句,只要让序列的输出值,大于表中主键字段的最大值即可。这一点实现起来并不难,关键是,如何确保表和序列的一一匹配?为此,需要设计表来保存两者的关系,如下结构:
create table t_bas_tabandseqs
(table_name varchar2(30) not null,
seq_name varchar2(30) not null,
column_name varchar2(30));
/
table_name :表名,必填项。
seq_name :该表主键对应的序列名,必填项。
column_name :表主键字段,辅助,主键只能一个字段。
alter table t_bas_tabandseqs add constraint pk_bas_tabandseqs primary key(table_name);
create unique index idx_ bas_tabandseqs on t_ bas_tabandseqs (seq_name);
--D 编写了个存储过程来修正序列的当前值,使得序列当前值大于表的主键最大值。
入参为:发生唯一性错误的索引;如上面的 PK_BD_SUPPLIER_L,
存储过程根据入参,找到所属的表,当此索引是由一个索引字段组成时,在辅助表:
t_bas_tabandseqs里搜索此表对应的序列,
然后对比表的主键最大值,及序列的下一个值,若序列值比主键最大值小,则更改序列步伐
属性(下个值跨过主键最大值),然后取序列的下一个值,此时,序列的当前值将大于主键最
大值,然后,再把序列的步伐改回1。
create or replace procedure p_bas_alterseqstartval(v_accid_idx in varchar2) as
v_maxval number;
v_nextval number;
v2_nextval number;
begin
for i in (select table_name, column_name, col_position from (select table_name, column_name, column_position col_position,
row_number() over(partition by table_name, index_name order by column_position desc) seq
from user_ind_columns where index_name=upper(v_accid_idx)) where seq=1 ) loop
if (i.col_position = 1) then
for j in (select seq_name from t_bas_tabandseqs where table_name=i.table_name) loop
begin execute immediate 'select '||j.seq_name||'.nextval from dual' into v_nextval;
execute immediate 'select max('||i.column_name||') from '||i.table_name into v_maxval;
if (v_maxval > v_nextval) then
execute immediate 'alter sequence '||j.seq_name||' increment by '||(v_maxval - v_nextval + 1);
execute immediate 'select '||j.seq_name||'.nextval from dual' into v2_nextval;
execute immediate 'alter sequence '||j.seq_name||' increment by 1';
elsif v_maxval = v_nextval then null;
elsif (v_maxval < v_nextval) then
raise_application_error(-20010,'序列值和主键值并无冲突,或者序列:'||j.seq_name||',并非给该主键使用.');
end if;
end;
end loop;
else raise_application_error(-20001,'该索引由多字段组成,得人工处理.'); end if;
end loop;
end;
/
ORACLE数据库:如何修正测试环境在插入数据时,出现唯一性错误
本文2024-09-23 01:16:56发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-144951.html