我正在使用Spring和Hibernate来开发Java中的Web应用程序。我们假设我有一张桌子。当我从该表中删除一些记录时,有时我需要重置主键字段的值。
假设我在表中有10条记录,我删除了最后5条记录。现在,当我插入新记录时,主键字段的值应该从6
开始,但它将从11
开始。
如果我需要在MySql中的6
(maximum +1
)处启动主键值,我只需要执行以下SQL语句。
alter table table_name auto_increment=1;
这会自动将auto_increment
的值重置为该字段的maximum + 1
值(概念上可能不正确但可行)。
在Oracle(10g)中,我正在使用sequence
主键。在从数据库中删除某些记录时,Oracle是否有办法将sequence
的值重置为maximum + 1
?
答案 0 :(得分:16)
如果您有20条记录并删除5-10条记录会怎样?你在中间有一个差距,重新设置序列将无法解决。序列将never generate a gap free sequence of numbers,一个完美的 1,2 .. n 。
如果您致电.nextval
但未使用该值已消失。你打算放弃并重新创建序列吗?如果您启动插入并取消它并且Oracle rolls back您已完成的操作,则这些值已消失。如果你设置nocache
那么你会有更少的差距但是会以牺牲性能为代价;这值得么?
您的缓存应设置为您希望在任何时间across all sessions执行的插入次数,以避免出现任何性能问题。序列旨在提供一种非常快速,可扩展的方式来创建代理键而无需任何锁等不来重新生成正整数集。
在一天结束时,丝毫没关系。如果你依靠一个完整的序列作为你的表的关键,那么你的数据而不是序列有问题。
要真正回答您的问题,您需要:
查找最大值意味着您需要动态地重新创建序列,但需要牺牲另一个性能。
如果您尝试在表格中插入某些内容,则会失败,并且可能会使使用该序列的任何触发器或其他对象无效:
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在评论中建议的那样,无需删除并重新创建序列的方法。
即:
id
与序列当前值之间的差异。 这样做的好处是对象仍然存在,因此仍然保持触发器,授权等。正如我所看到的那样,缺点是如果另一个会话与你的同时增加这个负数,你可以回到太远。
以下是演示:
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