Sql 发生异常时减少oracle序列
我尝试使用pl/sql在数据库中插入一条新记录,因此首先生成一个新序列,如下所示:Sql 发生异常时减少oracle序列,sql,oracle,plsql,Sql,Oracle,Plsql,我尝试使用pl/sql在数据库中插入一条新记录,因此首先生成一个新序列,如下所示: select my_seq.nextval into seqId from dual; 然后我尝试使用生成的seqId插入一条新记录,如下所示: insert into myTable (id) values seqId ; 但是,当插入过程中发生错误时,我希望在异常块中减少我的序列。有人有什么想法吗?在Oracle中,序列递增(序列递增或递减,而不是两者都递增)或重新初始化序列(从…开始)后,不能递减。没有
select my_seq.nextval into seqId from dual;
然后我尝试使用生成的seqId插入一条新记录,如下所示:
insert into myTable (id) values seqId ;
但是,当插入过程中发生错误时,我希望在异常块中减少我的序列。有人有什么想法吗?在Oracle中,序列递增(序列递增或递减,而不是两者都递增)或重新初始化序列(从…开始)后,不能递减。没有办法做到这一点。希望这有帮助 然而,如果你想继续这种荒谬的行为,你可以试试这个,但是你需要先初始化你的序列,即myseq.nextval强> 然后,您可以首先尝试插入currval,如果成功,则可以增加序列,否则序列将具有其先前的值
Declare
currval pls_integer;
inc pls_integer;
Begin
select seq.currval into currval from dual;
insert into myTable (id) values (currval) ;
select seq.nextval into inc from dual;
Exception
when others then
do the exception handling;
end;
正如已经告诉你的,你根本不应该这样做。不管怎样,你可以这样做 示例表和序列:
SQL> create table mytable (id number primary key);
Table created.
SQL> create sequence seq;
Sequence created.
SQL> set serveroutput on
SQL> select * from mytable;
ID
----------
1 --> populated with the first P_TEST call
2 --> populated manually
SQL> select seq.nextval from dual;
NEXTVAL
----------
1 --> sequence is decremented from 2 to 1
将seq.nextval
插入mytable
并在出现故障时递减序列的过程。我用一种最简单的方法来做这件事——将start
参数设置为上次获取的值减去1,然后删除它并重新创建<这里的代码>DBMS_输出调用只是为了显示过程中发生了什么
SQL> create or replace procedure p_test as
2 seqid number;
3 begin
4 seqid := seq.nextval;
5 dbms_output.put_line('Sequence number to be inserted = ' || seqid);
6
7 insert into mytable(id) values (seqid);
8
9 exception
10 when others then
11 dbms_output.put_line(sqlerrm);
12 execute immediate 'drop sequence seq';
13 execute immediate 'create sequence seq start with ' || to_char(seqid - 1);
14 end;
15 /
Procedure created.
让我们测试一下:这应该插入1
:
SQL> exec p_test;
Sequence number to be inserted = 1
PL/SQL procedure successfully completed.
SQL> select * from mytable;
ID
----------
1
到目前为止还不错。现在,我将手动插入ID=2
,以便下一个过程调用违反唯一约束:
SQL> insert into mytable values (2);
1 row created.
再次调用该过程:
SQL> exec p_test;
Sequence number to be inserted = 2
ORA-00001: unique constraint (SCOTT.SYS_C007547) violated
PL/SQL procedure successfully completed.
嗯,;程序以静默方式完成。它没有插入任何内容,但减少了顺序:
SQL> create table mytable (id number primary key);
Table created.
SQL> create sequence seq;
Sequence created.
SQL> set serveroutput on
SQL> select * from mytable;
ID
----------
1 --> populated with the first P_TEST call
2 --> populated manually
SQL> select seq.nextval from dual;
NEXTVAL
----------
1 --> sequence is decremented from 2 to 1
如果我删除有问题的ID=2
并重试:
SQL> delete from mytable where id = 2;
1 row deleted.
SQL> exec p_test;
Sequence number to be inserted = 2
PL/SQL procedure successfully completed.
SQL> select * from mytable;
ID
----------
1
2
SQL> select seq.nextval from dual;
NEXTVAL
----------
3
SQL>
对,;有点效果,但不值得这么痛苦
此外,正如您所评论的,一个表中有20行。如果有人删除第13行,你会怎么做。是否将所有介于#14和20之间的值递减?如果这是一个主键,由一些外键引用,该怎么办
说真的,不要这样做。你为什么要这样做?你“想要”的东西毫无意义;“想要”表示您不了解主键在关系数据库中应该如何工作。在ID的序列中绝对没有有效的理由想要“无间隙”。除了所有其他的注释之外,你还需要考虑如何在真实的多用户环境中工作。会话A获取序列21。然后会话B获得序列22。现在会话A希望回滚序列。但是会话B与序列22配合得很好。如果您实际实现了这个,那么让我们来检查一个结果。现在请记住,序列是共享对象。UserA运行他们的进程并获取序号21,将next_val增加到22。现在,您的进程将得到序号22,并将下一个值增加到23。您的进程将插入ID22。此时,一个进程有一个异常,将next_val递减到22。您的过程将继续,并且需要另一个序号,因此您将得到next_val 22并增加到23。然后你插入并得到“dup\u val\u on_index”异常——你无法找到它。现在下一个价值是什么?你的应用程序运行得如何。其他现实世界的注意事项:1)序列通常需要缓存一系列值,以满足用户需求。如果发生诸如数据库重启之类的情况,任何缓存但未使用的值都将丢失。下次缓存值时,它们将从上一次缓存停止的位置开始,即使未使用该范围内的所有值。2) 在RAC情况下,每个实例都将有一个单独的缓存,其中包含自己的值。。。强制序列始终递增1根本不可伸缩,更不用说没有间隔的想法了。在多用户环境中行不通,@sandyv。迟早会有两个(或更多)用户获取相同的最大值,向其中添加1,并且只有第一个提交的用户才能插入行。其他所有人都会因为唯一约束冲突而失败。这不起作用,因为为了使用CURRVAL,您首先必须获取NEXTVAL。因此,您的代码将失败,因为
ORA-08002:sequence SEQ.CURRVAL在此会话中尚未定义
“但是您需要首先初始化您的序列,即myseq.nextval;”您没有完全读取所以为真!我读代码,而不是文字。很抱歉。关于使用标识栏,我对该主题了解不多。在后台,标识栏使用了一个序列,因此对于您想要的内容来说,这不会有太大的改进。此外,为了使用它,您的数据库版本必须是12c及以上。