Sql 发生异常时减少oracle序列

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中,序列递增(序列递增或递减,而不是两者都递增)或重新初始化序列(从…开始)后,不能递减。没有

我尝试使用pl/sql在数据库中插入一条新记录,因此首先生成一个新序列,如下所示:

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及以上。