需要重置Oracle中序列的值

Bha*_*esh 6 java oracle spring hibernate oracle10g

我正在使用Spring和Hibernate来开发Java中的Web应用程序.我们假设我有一张桌子.当我从该表中删除一些记录时,有时我需要重置主键字段的值.

假设我在表中有10条记录,我删除了最后5条记录.现在,当我插入新记录时,主键字段的值应该从at开始,6但它将从那里开始11.

如果我需要在MySql 中的6(maximum +1)处启动主键值,我只需要执行以下SQL语句.

alter table table_name auto_increment=1;
Run Code Online (Sandbox Code Playgroud)

这将自动重置价值auto_increment,以maximum + 1该字段的值(在概念是不正确的,但它的工作原理).

在Oracle(10g)中,我正在使用sequence主键.在从数据库中删除某些记录时,Oracle是否有办法重置sequenceto maximum + 1值?

Ben*_*Ben 16

如果您正在使用该值,则不应重置该值的原因:

如果您有20条记录并删除5-10条记录会怎样?你在中间有一个差距,重新设置序列将无法解决.序列永远不会产生无间隙的数字序列,完美的1,2 ... n.

如果你打电话.nextval而不使用价值它就消失了.你打算放弃并重新创建序列吗?如果您启动插入并取消它并且Oracle 回滚您已完成的操作,那么这些值就会消失.如果你设定nocache那么你会有更少的差距但是以牺牲性能为代价; 这值得么?

您的缓存应设置为您希望在所有会话中一次执行的插入次数,以避免任何性能问题.序列旨在提供一种非常快速,可扩展的方法来创建代理键而无需任何锁等,而不是重新生成正整数集.

在一天结束时,一点也​​不重要.如果你依赖一个完整的序列作为你的表的关键,那么你的数据而不是序列有问题.


回答这个问题:

要真正回答您的问题,您需要:

  1. 首先,找出表中最大id(序列)值.
  2. 然后放下并重新创建序列.

查找最大值意味着您需要动态地重新创建序列,但需要牺牲另一个性能.

如果在发生这种情况时尝试将某些内容插入到表中,则会失败,并且可能使使用该序列的任何触发器或其他对象无效:

declare

   l_max_value number;

begin

   select max(id)
     into l_max_value
     from my_table;

   execute immediate 'drop sequence my_sequence_name';

   -- nocache is not recommended if you are inserting more than
   -- one row at a time, or inserting with any speed at all.
   execute immediate 'create sequence my_sequence_name
                           start with ' || l_max_value
                      || ' increment by 1
                           nomaxvalue
                           nocycle
                           nocache';

end;
/
Run Code Online (Sandbox Code Playgroud)

正如我所说,不推荐这样做,你应该忽略任何差距.


更新 - 更好的答案感谢Jeffrey Kemp:

与文档的建议相反,正如Jeffrey Kemp在评论中建议的那样,可以在丢弃和重新创建序列的情况下执行此操作.

即,通过:

  1. 计算id表中最大值与序列当前值之间的差异.
  2. 通过此负数更改序列以增加
  3. 改变序列再次增加1.

这样做的好处是对象仍然存在,因此仍然保持触发器,授权等.正如我所看到的那样,缺点是如果另一个会话与你的同时增加这个负数,你可以回到太远.

这是一个演示:

设置测试:

SQL> create sequence test_seq
  2   start with 1
  3   increment by 1
  4   nomaxvalue
  5   nocycle
  6   nocache;

Sequence created.

SQL>
SQL> create table tmp_test ( id number(16) );

Table created.

SQL>
SQL> declare
  2     l_nextval number;
  3  begin
  4
  5    for i in 1 .. 20 loop
  6       insert into tmp_test values ( test_seq.nextval );
  7    end loop;
  8
  9  end;
 10  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        20

SQL>
SQL> delete from tmp_test where id > 15;

5 rows deleted.

SQL> commit;

Commit complete.
Run Code Online (Sandbox Code Playgroud)

恢复序列

SQL>
SQL> declare
  2
  3     l_max_id number;
  4     l_max_seq number;
  5
  6  begin
  7
  8     -- Get the maximum ID
  9     select max(id) into l_max_id
 10       from tmp_test;
 11
 12     -- Get the current sequence value;
 13     select test_seq.currval into l_max_seq
 14       from dual;
 15
 16     -- Alter the sequence to increment by the difference ( -5 in this case )
.
 17     execute immediate 'alter sequence test_seq
 18                          increment by ' || ( l_max_id - l_max_seq );
 19
 20     -- 'increment' by -5
 21     select test_seq.nextval into l_max_seq
 22       from dual;
 23
 24     -- Change the sequence back to normal
 25     execute immediate 'alter sequence test_seq
 26                          increment by 1';
 27
 28  end;
 29  /

PL/SQL procedure successfully completed.

SQL>
SQL> select test_seq.currval from dual;

   CURRVAL
----------
        15

SQL>
Run Code Online (Sandbox Code Playgroud)


Rei*_*ein 7

以下也适用(将序列值增加100):

select my_sequence.nextval from dual connect by level <= 100;
Run Code Online (Sandbox Code Playgroud)


Rav*_*ddy 5

参考Oracle的ALTER SEQUENCE文档,

  • 要以不同的数字重新启动序列,您必须删除并重新创建它.

您需要传递主键列的当前最大值以生成下一个序列号.
如果您继续删除某些最新记录,并希望重用已生成的序列值,则可能需要一次又一次地重新启动此序列.如果服务器在序列准备好服务之前收到下一个值的请求,则删除序列可能会导致SQLException.

您还可以在此处找到有关Oracle Sequences的一些有用说明.