暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 数据类型Number导致数值溢出,尽管值足够小

askTom 2016-08-30
1310

问题描述

尝试以下测试用例:
宣布
x编号:= 1 ;
开始
x := 1024 * 1024 * 1024 * 5 ;
结束;
/
-> ORA-01426 :数值溢出

宣布
x编号:= 1 ;
开始
x := x * 1024 ;
x := x * 1024 ;
x := x * 1024 ;
x := x 5 ;
结束;
/
->这样就可以了

示例可以在各种变体中完成,例如

宣布
*编号:= 1024 * 1024 * 1024 * 5 ;
开始
无效;
结束;
/

似乎如果构造了超过3个运算符,并且值超过了小整型,就会发生溢出。以后,你可以做任何事。

和: (我觉得很有趣) :
宣布
*编号;
开始
选择1024 * 1024 * 1024 * 1024 * 5进入x从双通道;
结束;
/
这个也行。

有什么想法吗?

敬重
最大



专家解答

当您在PL/SQL中乘以整数时,它实际上使用的是pls_integers。这些算法使用硬件算法。这比数字运算快。他们用图书馆的算术。

但有一个陷阱。上限为2,147,483,647。你的1024 * 1024 * 1024 * 1024 * 5的计算超过了这个!您将达到1024 * 1024 * 1024 * 2的限制:

SQL> declare
  2    l number := 1024 * 1024 * 1024  * 2;
  3  begin
  4    null;
  5  end;
  6  /
declare
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at line 2


但为什么会失败呢?

从文档中:

A calculation with two PLS_INTEGER values that overflows the PLS_INTEGER range raises an overflow exception, even if you assign the result to a NUMBER data type

https://docs.oracle.com/cloud/latest/db112/LNPLS/datatypes.htm#LNPLS99938

那么如何避免这种情况呢?

将表达式中的某个值设为数字!然后, Oracle将隐式地将整个计算转换为数字算术。

以下是您可以使用的几种方法:

Cast one of the literals

SQL> declare
  2    l number := cast(1024 as number) * 1024 * 1024  * 2;
  3  begin
  4    null;
  5  end;
  6  /

PL/SQL procedure successfully completed.


Add a decimal to one of the literals, making it a number

SQL> declare
  2    l number := 1024 * 1024 * 1024  * 2.0;
  3  begin
  4    null;
  5  end;
  6  /


Include a variable that's a number in the calculation

SQL> declare
  2    n number := 1;
  3    l number := n * 1024 * 1024 * 1024  * 2;
  4  begin
  5    null;
  6  end;
  7  /


这就是为什么你的第二个例子会起作用。所有的乘法都使用数算术。所以不要有2 147 483 647的限制。

SQL语句可以工作,因为它是在SQL引擎中处理的。PLS_integer不存在。所以它使用了数算。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论