1

我有一个脚本,我想在其中有一个全局变量来存储事务编号以供以后使用。该代码在我获取的序列值相对较低的一个模式上运行良好。它不适用于具有更高序列值的另一个模式,我得到“数字溢出”。如果我将该序列值更改为较低的数字,它也可以正常工作,但这不是一个选项。

VAR TRANSACTIONNR NUMBER;

BEGIN
  --Works with        NEXTVAL being around  946713241
  --Doesn't work with NEXTVAL being around 2961725541
  SELECT MY_SEQUENCE.NEXTVAL INTO :TRANSACTIONNR FROM DUAL;
  MY_PACKAGE.STARTTRANSACTION(:TRANSACTIONNR);
END;
/

  -- SQL Statements

BEGIN
  MY_PACKAGE.ENDTRANSACTION;
  MY_PACKAGE.DO_SOMETHING(:TRANSACTIONNR);
END;
/

同样有效的是将序列选择到 DECLARE 块中声明的变量中:

DECLARE
  TRANSACTIONNR NUMBER;
BEGIN
  SELECT MY_SEQUENCE.NEXTVAL INTO TRANSACTIONNR FROM DUAL;
  MY_PACKAGE.STARTTRANSACTION(TRANSACTIONNR);
END;
/

但这意味着我将无法在最后的块中重用它。无法设置数字的大小。

VAR TRANSACTIONNR NUMBER(15)

无效。

有什么想法我可以尝试或其他方法来存储全局状态吗?

4

1 回答 1

1

在进一步的调查中,这看起来可能是一个 SQL Developer 错误(当然,假设你再次在做什么......)。我可以得到同样的错误:

VAR TRANSACTIONNR NUMBER;

BEGIN
  SELECT 2961725541 INTO :TRANSACTIONNR FROM DUAL;
END;
/

似乎 SQL DeveloperNUMBER仅限于2^31,而 Oracle 通常不是这种情况。

一种可能的解决方法是用于BINARY_FLOAT存储该值,但您最终会遇到精度问题(不确定在哪里,但看起来可以2^53-ish),并且在使用它时需要将cast()其恢复NUMBER

VAR TRANSACTIONNR BINARY_DOUBLE;

BEGIN
  SELECT 2961725541 INTO :TRANSACTIONNR FROM DUAL;
  -- dbms_output.put_line(cast(:TRANSACTIONNR as NUMBER)); -- null for some reason
END;
/

...

BEGIN
  dbms_output.put_line(cast(:TRANSACTIONNR as NUMBER));
END;
/

出于某种原因,我似乎无法在我设置的匿名块中再次引用绑定变量——它在注释掉的代码中为空——这似乎是另一个 SQL Developer 怪癖,无论var类型如何;但是当你在你的代码中这样做时,我可能再次假设太多......


后代的原始答案,因为它可能在其他情况下仍然相关......

大概你正在做一些事情来结束当前的交易,例如 a commitin endtransaction; 否则你可以my_sequence.currvaldo_something通话中提及。但是,对于这种大小的number数字,变量是可以的,它不会对大小的序列产生任何影响,并且它来自序列而不是手动分配不会有任何区别。我认为问题不在于存储或顺序。

错误似乎更有可能来自您正在调用的包过程之一,尽管我无法想象您可能会用它做什么;像这样的事情会导致同样的错误:

create sequence my_sequence start with 2961725541;

create package my_package as
procedure starttransaction(v_num number);
procedure endtransaction;
procedure do_something(v_num number);
end my_package;
/

create package body my_package as

procedure starttransaction(v_num number) is
begin
    dbms_output.put_line('starttransaction(): ' || v_num);
    for i in 1..v_num loop
        null;
    end loop;
end starttransaction;

procedure endtransaction is
begin
    dbms_output.put_line('endtransaction()');
end endtransaction;

procedure do_something(v_num number) is
begin
    dbms_output.put_line('do_something(): ' || v_num);
end do_something;

end my_package;
/

当您的代码针对它运行时,它会引发您的错误:

BEGIN
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at "STACKOVERFLOW.MY_PACKAGE", line 6
ORA-06512: at line 5


endtransaction()
do_something():

请注意,该错误是针对包中的第 6 行报告的,这是该for ... loop行,而不是来自匿名块中的分配。

像这样循环当然是一件奇怪的事情,但可能还有其他方法可以产生该错误。它工作的断点是如果在nextval上面2^31。如果我以 2147483647 开始序列,它可以工作,而 2147483648 则错误。

我假设您实际上是ORA-01426从原始问题中得到的;如果它实际上是 a ORA-1438ORA-06502则通过尝试将值分配给number(9)列或变量来更容易重现。不过,“数字溢出”非常具体。

于 2012-10-23T14:19:01.350 回答