将大序列值选择为不在PL / SQL代码中工作的全局变量

时间:2012-10-23 10:07:37

标签: sql oracle plsql

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

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)

无效。

我可以尝试的任何想法或其他存储全球状态的方法吗?

1 个答案:

答案 0 :(得分:1)

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

VAR TRANSACTIONNR NUMBER;

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

似乎SQL Developer NUMBER仅限于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类型;但正如你在代码中所做的那样,我可能会再次假设太多......


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

据推测,你正在做一些事情以结束当前的交易,例如commit中的endtransaction;否则,您可以在my_sequence.currval来电中引用do_somethingnumber变量对于这个数量的大小是好的,但它对于大小的序列没有问题,并且它不会与序列而不是手动分配有任何区别。我认为问题不在于存储或序列。

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

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;如果它实际上是ORA-1438ORA-06502,那么通过尝试将值分配给number(9)列或变量,可以更容易地重现。 “数字溢出”非常具体。