需要重置Oracle中序列的值

时间:2012-04-15 05:41:30

标签: java oracle spring hibernate oracle10g

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

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

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

alter table table_name auto_increment=1;

这会自动将auto_increment的值重置为该字段的maximum + 1值(概念上可能不正确但可行)。

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

4 个答案:

答案 0 :(得分:16)

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

如果您有20条记录并删除5-10条记录会怎样?你在中间有一个差距,重新设置序列将无法解决。序列将never generate a gap free sequence of numbers,一个完美的 1,2 .. n

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

您的缓存应设置为您希望在任何时间across all sessions执行的插入次数,以避免出现任何性能问题。序列旨在提供一种非常快速,可扩展的方式来创建代理键而无需任何锁等来重新生成正整数集。

在一天结束时,丝毫没关系。如果你依靠一个完整的序列作为你的表的关键,那么你的数据而不是序列有问题。


回答问题:

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

  1. 首先,找出表中最大id(序列)值是什么。
  2. 然后drop and re-create the sequence
  3. 查找最大值意味着您需要动态地重新创建序列,但需要牺牲另一个性能。

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

    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;
    /
    

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


    更新 - 更好的回答感谢Jeffrey Kemp

    与文档的建议相反,正如Jeffrey Kemp在评论中建议的那样,无需删除并重新创建序列的方法。

    即:

    1. 计算表中最大id与序列当前值之间的差异。
    2. 通过此负数改变序列以增加
    3. 改变序列再次增加1。
    4. 这样做的好处是对象仍然存在,因此仍然保持触发器,授权等。正如我所看到的那样,缺点是如果另一个会话与你的同时增加这个负数,你可以回到太远。

      以下是演示:

      设置测试:

      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.
      

      还原序列

      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>
      

答案 1 :(得分:7)

以下也有效(将序列值增加100):

select my_sequence.nextval from dual connect by level <= 100;

答案 2 :(得分:5)

参考Oracle的ALTER SEQUENCE文档,

  • 要以不同的号码重新启动序列,您必须删除和 重新创造它。

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

您还可以在Oracle Sequences here上找到一些有用的说明。

答案 3 :(得分:0)

这个技巧对我有用。 在我的序列(USERSUTPL_USERUTPL_SQ)中,最后一个数字是53。 我表中的最后一个id是83

SELECT MAX(ID) FROM USERSUTPL_USERUTPL

然后83-53 = 31.所以:

ALTER SEQUENCE USERSUTPL_USERUTPL_SQ INCREMENT BY +31;
SELECT USERSUTPL_USERUTPL_SQ.NEXTVAL FROM dual;
ALTER SEQUENCE USERSUTPL_USERUTPL_SQ INCREMENT BY 1;

它改变了最后一个数字。 :d