1

我想知道为什么以下 SEQUEL 计算不能正常工作,它们似乎更多地基于内容而不是语法。这一切都始于我们的一个观点(帮助系统)后续查询未能正确计算一列的一行数据(不是所有行)。我从 Sequel Viewpoint 应用程序中复制了代码并直接粘贴到STRSQLiseries 上并体验了相同的结果。您将看到下面使用值 922.459 进行的计算——其中一个导致++++,一个产生正确的值(不带括号),一个计算正确但计算精简。您还会看到 50 的值 - 结果为零,而 1 使用 50.5 显示正确的结果。我收到数据十进制错误,但当然没有什么可以帮助我理解原因——尤其是因为我正在处理所有硬编码的数字。我确实发现了一件事——如果我将数字从 50 更改为 50.0——计算是正确的。但是,如果我对数字 922 执行相同操作 - 922 和 922.0 都会导致+++. 有任何想法吗?

SELECT  Bprod,(1.1*1/1)*(922.459*1/1000)*1.06 
FROM    BOMBYITEM                                    

产量:

Item                                               Numeric Expression   
Number                                                                  
124927                               +++++++++++++++++++++++++++++++++  

尽管:

SELECT   bprod,1.1*1/1 * 922.459*1/1000 *1.06 
FROM     BOMBYITEM                              

产量:

Item                                                 Numeric Expression   
Number                                                                    
124927                                       1.075587194000000000000000   

和:

SELECT  bprod,(1.1)*(.922459) *1.06   
FROM    BOMBYITEM                       

产量:

Item                                 Numeric Expression 
Number                                                  
124927                                   1.075587194    

和:

SELECT  Bprod,(1.1*1/1)*(50*1/1000)*1.06   
FROM    BOMBYITEM                                 

产量:

Item                                                  Numeric Expression 
Number                                                                   
124927                                            .000000000000000000000

和:

SELECT  Bprod,(1.1*1/1)*(50.5*1/1000)*1.06 
FROM    BOMBYITEM                                 

产量:

Item                                               Numeric Expression    
Number                                                                   
124927                               .0588830000000000000000000000000
4

3 回答 3

3

您所说的“更多地基于内容而不是语法”是许多计算环境中操作的常见属性,而不仅仅是在 DB2 SQL 中。正在发生的事情是,在没有明确类型信息的情况下,评估引擎正在从值的表达方式推断类型。

最容易理解的例子是全整数算术。50和的区别在于50.0隐含类型50整数,而隐含类型50.0某种小数或浮点数。当两个操作数都是整数时,一些评估引擎只进行整数运算,并产生整数结果。So9/3被评估为3,但10/3和也是如此11/312/3被评估为41/3并且2/3都被评估为0. 因此,这解释了结果为 0 的示例。(50*1/1000)仅涉及整数,因此计算结果为0,使整个表达式计算结果为 0。

现在,十进制和浮点运算更难推理,因为有很多方法可以表示这些数字,而且它们的精度规则通常非常神秘。数据库尤其容易同时具有以 10 为底的固定精度小数以及 IEEE 浮点,它们是完全不同的系统,它们都不能准确地表示对人类来说简单到三分之一的数学量。

在 DB2 SQL 的情况下,您的值是固定精度小数,一旦超出精度限制,结果就会爆炸。不幸的是,我无法准确解释为什么您的值超出了精度的限制,因为我自己也不了解规则。(我尽量不在 SQL 中做很多算术!)您可能想尝试阅读这里:

结果数据类型的规则

虽然 JamesA 的示例不能直接帮助您,但如果您明智地将显式精度规范应用于表达式的组件,以影响中间结果的精度,您仍然可以从他的建议中受益。例如:

SELECT (1.1) * (922.459/1000) * 1.06 FROM BOMBYITEM

不起作用,但这确实:

SELECT (1.1) * DEC(922.459/1000, 31, 15) * 1.06 FROM BOMBYITEM

请注意,您的括号会强制执行某些不利的操作顺序。我的非工作示例可以通过删除括号来工作:

SELECT 1.1 * 922.459/1000 * 1.06 FROM BOMBYITEM

如果我使用小数或浮点数而不是整数,它也可以工作:

SELECT (1.1) * (922.459/1000.0) * 1.06 FROM BOMBYITEM

除非您知道自己在做什么,否则我建议 (1) 仅在逻辑必要时使用括号,以及 (2) 在最终产生小数或浮点结果的计算中避免使用整数。这些可能会给评估引擎提供完成计算的最佳机会。

于 2013-11-19T22:29:20.057 回答
3

此答案基于来自IBM InfoCenter for iSeries 7.1 的信息、带有算术运算符的 SQL 表达式以及其下方的“SQL 中的十进制算术”页面。

SQL 中的所有数字都有精度(总位数)和小数位数(小数位数)。当您定义一个变量或列时,您可以直接声明精度和比例尺Declare My_Number as Decimal(11,6)(最多 99,999.999999 的数字:11 位,其中 6 位在小数点后)。SQL 默认最大精度和小数位数为 31。(您可以通过显式声明将最大值提高到 63。)

当您执行计算时,SQL 会尽可能地尝试在不损失计算准确性的情况下进行数学运算。在加法、减法和/或乘法的情况下,这是对结果精度和比例的相当直接的修改。

然而,对于除法,SQL 基本上会在结果中抛出尽可能多的规模。

因此,当您指定像 (1.1*1/1) 这样的操作时,SQL 会将其解释为:

1.1 * 1 = 一个小数(5,1)乘以一个整数;int 被提升为小数(5,0),结果是小数(10,1)。(较大的整数值将被提升为小数(11, 0)或小数(19,0)。)(注意,我实际上不确定分配给文字值的精度;在docs。但是由于您指定了 1 个小数位,因此比例肯定是 1。)

(decimal(10,1) / 1) = 将 decimal(10,1) 除以 int:Int 被提升为进程的 (decimal(5,0))。这导致小数(31,21)或大约。

当你得到 50 / 1000 时,即整数除法,因此产生一个整数,显然等于 0。将其更改为 50.0 / 1000,你将得到与前面计算相同的基本过程,产生另一个小数(10, 21)。

然后你再次相乘:

小数(31,21) * 小数(31,21) = 小数(63,31) (中间结果)

小数(63,31) * 小数(5,2) = 小数(63,31) (最终结果)

最终结果显示小数点后 31 位。

对于产生 +++++++ 结果的初始操作,可能会正确计算答案,但最终会得到一个非常宽格式的数字,例如小数 (63,31),这对于显示器; 而对于 DOES 产生结果的版本,由于您没有使用括号强制操作顺序,因此一个或多个中间结果会降低足够的精度和/或比例,最终结果现在足够短以正确显示。

于 2013-11-19T22:35:33.003 回答
2

在执行十进制计算时,您应该使用ROUND和/或DECIMAL明确定义预期的精度和比例。

SELECT Bprod, ROUND((1.1*1/1)*(922.459*1/1000)*1.06, 2) FROM BOMBYITEM
于 2013-11-18T21:49:43.037 回答