0

我们在 Oracle DB 版本 21.3 上发现了一个错误(同样也在 19.3 版本上进行了测试)。如果您在插入语句中使用函数并使用返回子句返回值,则结果是您在插入语句中调用的函数执行两次!!!

下面是一个使用为序列创建下一个值的函数的示例。我知道您可以直接使用“.nextval”(如图所示工作正常),但这只是演示函数双重执行的示例。我可以使用任何其他函数并且会被执行两次(例如计算某些东西)。

您可以使用此示例测试它的工作原理:

create sequence seq_1;
create sequence seq_2;
create table test1000 (id number, a varchar2(4004));
create table test1001 (id number, a varchar2(1001));
create or replace function testfun return number is
  v_a number;
begin
  select seq_1.nextval into v_a from dual;
  dbms_output.put_line('FUNCTION RETURNS SEQ_1 VALUE: '||v_a);
  return v_a;
end;
/

如果你执行这个,你可以测试这个:

declare
  v_a varchar2(100);
begin
  insert into test1000(id, a) values (seq_2.nextval, 'SEQ_1:'||testfun) returning a into v_a;
  dbms_output.put_line(v_a);
  insert into test1001(id, a) values (seq_2.nextval, 'SEQ_1:'||testfun) returning a into v_a;
  dbms_output.put_line(v_a);
end;
/

它将输出:

FUNCTION RETURNS SEQ_1 VALUE: 1
SEQ_1:1
FUNCTION RETURNS SEQ_1 VALUE: 2
FUNCTION RETURNS SEQ_1 VALUE: 3
SEQ_1:3

您可以在第二次插入中看到双重执行。表 test1001 中的数据值为 2,但变量 v_a 中返回的值不同(值为 3)。在第一次插入中没有发生双重执行,而是在第二次中发生。我相信这是因为第二个表具有字段“a”,其中 varchar2 的最大大小高于 4000,我相信这与 oracle 如何处理扩展的 varchar2 类型(MAX_STRING_SIZE 在我们的数据库中扩展)有关。

我向 Oracle 报告了这个错误。当我收到他们的回复时,我会更新这个......

4

1 回答 1

0

上样的解法很简单。直接使用“.nextval”即可。如果您有任何不同的函数,解决方案是在插入语句中使用它之前执行该函数(并将结果保存在变量中),如下所示:

declare
  v_a varchar2(100);
  v_seq_id number;
begin
  v_seq_id := testfun;
  insert into test1000(id, a) values (seq_2.nextval, 'SEQ_1:'||v_seq_id) returning a into v_a;
  dbms_output.put_line(v_a);
  v_seq_id := testfun;
  insert into test1001(id, a) values (seq_2.nextval, 'SEQ_1:'||v_seq_id) returning a into v_a;
  dbms_output.put_line(v_a);
end;
/

结果将是正确的:

FUNCTION RETURNS SEQ_1 VALUE: 1
SEQ_1:1
FUNCTION RETURNS SEQ_1 VALUE: 2
SEQ_1:2
于 2021-11-29T09:46:22.360 回答