oracle 序列值导致的主键冲突问题

背景:操作中我是先导出了数据库的结构(包括序列),再导入数据(数据来自另一个库)。这导致了部分表相应的序列值(比如表YK_YKLB,用序列SEQ_YK_YKLB的值来作为表的主键值)小于主键的最大值,这样插入数据时会报错主键冲突。

解决方法:希望将有问题的序列值增大到表的主键最大值+50

(当然啦有一种更简单粗暴的方法,就是把所有的序列值统统往上加800 或者更大,但这种方法未必能解决所有问题,可能有漏网之鱼。下面是一种更精准的方法,直接比较表主键最大值和相应序列值)

第一步:找出主键为单列的表(多列构成联合主键的情况,插入数据时不会仅从序列取值作为主键,不会出现问题)和主键所在的列

SELECT max(COLUMN_NAME) col,max(TABLE_NAME) t
FROM user_cons_columns 
WHERE constraint_name IN (select constraint_name from user_constraints WHERE constraint_type ='P') --筛选主键约束
GROUP BY CONSTRAINT_NAME 
HAVING count(1) = 1

第二步:找出这些表的主键的最大值、表的序列的当前值

新建MAXVAL_SEQVAL_TABLE表,这个表包含3各字段:MAXVAL(表的主键的最大值),SEQVAL(表的序列的当前值),TABLENAME(表名)

▲执行此语句 建表语句:

create table MAXVAL_SEQVAL_TABLE(MAXVAL varchar2(100),SEQVAL varchar2(100),TABLENAME varchar2(100));

将各个表的主键最大值、序列值、表名找出来,插入MAXVAL_SEQVAL_TABLE表。

▲执行此语句 查询语句,拼接sql

select max(COLUMN_NAME) col, max(TABLE_NAME) t, 'INSERT INTO maxval_seqval_table SELECT (select max(' || max(COLUMN_NAME)|| ') from ' || max(TABLE_NAME)|| ') maxVal,SEQ_' || max(TABLE_NAME)|| '.nextval AS seqval, ''' || max(TABLE_NAME)|| ''' AS t FROM dual;'
from user_cons_columns
where constraint_name in (select constraint_name
from user_constraints
where constraint_type = 'P')--筛选主键约束
and ('SEQ_' || TABLE_NAME) in (select sequence_name
from USER_SEQUENCES)
group by CONSTRAINT_NAME
having count(1) = 1;

结果是这样的:

5914638086b049449d1b6a84a3d3cf6c.png

 ▲执行此语句 将查询结果的sql语句复制出来,执行

就将所有有用的数据插入到了MAXVAL_SEQVAL_TABLE表。表中的数据如下:

2b8b2d34c7bf423ebc16be02e57209f6.png

第三步:将序列(假定序列都是以规范的方式:SEQ_表名命名的)值改为相应表的主键最大值+50

▲执行此语句 新建一列MAXVAL_add,存储主键值+50的值

alter table MAXVAL_SEQVAL_TABLE add MAXVAL_add number;
update MAXVAL_SEQVAL_TABLE set MAXVAL_add = TO_NUMBER(MAXVAL) + 50;

有了MAXVAL_SEQVAL_TABLE表,下面就很好办了。删除、重建序列的语句拼接一下

▲执行此语句 将下面查询结果复制到sql窗口或控制台中执行

SELECT 
'DROP SEQUENCE SEQ_'||TABLENAME||';CREATE SEQUENCE SEQ_'||TABLENAME||' INCREMENT BY 1 MINVALUE 1 MAXVALUE 9999999999 NOCYCLE CACHE 20 NOORDER start WITH '||maxVal_Add||';'
FROM maxval_seqval_table WHERE TO_NUMBER(MAXVAL) >= TO_NUMBER(SEQVAL)

注意:这里的条件一定要是TO_NUMBER(MAXVAL) >= TO_NUMBER(SEQVAL),不能少了TO_NUMBER!!否则就是字符串的比较,没有意义

查询结果复制出来,执行

执行完后,可将MAXVAL_SEQVAL_TABLE表删除,因为表中数据只能反映上次静态收集的信息。

所有有问题的序列值就都更改啦!再也不会有插入数据主键冲突的问题!

后来想了一下,这个方法也有一些缺陷,比如序列的命名是否规范。如果序列和表不是按照规范命名的,那就白搭了。。序列是怎么命名的,还要研究一下orm框架,比如本项目用的是hibernate。

注意:此方法最好在业务停止或很少的时候执行,因为涉及到删除与重建序列,可能与正在进行的业务冲突

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值