db2 为什么这些百分比之和不是100%?

zzlelutf  于 2022-11-07  发布在  DB2
关注(0)|答案(3)|浏览(232)

我在DB2SQLDB中有一系列的计算时间,它们存储为float,默认值为0.0。
正在更新的表如下:

CREATE TABLE MY_CALC_DATA_TABLE
(
    CALCDATE                 TIMESTAMP,
    INDIV_CALC_DURATION_IN_S FLOAT WITH DEFAULT 0.0,
    CALC_TIME_PERCENTAGE     FLOAT WITH DEFAULT 0.0
)

使用一个存储过程。我计算的总和如下:

CREATE OR REPLACE PROCEDURE MY_SCHEMA.MY_SPROC (IN P_DATE TIMESTAMP)
    LANGUAGE SQL
    NO EXTERNAL ACTION
BEGIN
    DECLARE V_TOTAL_CALC_TIME_IN_S FLOAT DEFAULT 0.0;

    -- other stuff setting up and joining data

    -- Calculate the total time taken to perform the
    -- individual calculations

    SET V_TOTAL_CALC_TIME_IN_S =
        (
            SELECT
                SUM(C.INDIV_CALC_DURATION_IN_S)
            FROM
                MY_SCHEMA.MY_CALC_DATA_TABLE C
            WHERE
                C.CALCDATE = P_DATE
        )

    -- Now calculate each individual calculation's percentage
    -- of the toal time.

    UPDATE
        MY_SCHEMA.MY_CALC_DATA_TABLE C
    SET
        C.CALC_TIME_PERCENTAGE =
            (C.INDIV_CALC_DURATION_IN_S / V_TOTAL_CALC_TIME_IN_S) * 100
    WHERE
        C.CALCDATE = P_DATE;

END@

问题是,当我对指定CALC_DATE的所有CALC_TIME_PERCENTAGE值求和时,它总是小于100%,而对于不同的CALC_DATES,求和值为80%或70%。
我们在这里讨论的是35k到55k的计算,如上所述,单个计算占总计算的最大百分比为11%,* 批 * 计算在0.00000N%范围内。
要计算总百分比,我使用简单查询:

SELECT
    SUM(C.CALC_TIME_PERCENTAGE)
FROM
    MY_SCHEMA.MY_CALC_DATA_TABLE C
WHERE
    C.CALCDATE = P_DATE;

有什么建议吗?

**更新:**按照建议重新排列计算,修复了问题。谢谢。顺便说一句,在DB2中,FLOAT和DOUBLE是相同的类型。现在阅读关于float的建议文章。

5anewei6

5anewei61#

如果字段C.INDIV_CALC_DURATION_IN_S是Integer,我会假设它是一个舍入错误。再次阅读,这不是问题,因为数据类型是FLOAT
你仍然可以尝试使用这个方法。如果这个方法产生的结果与之前的方法略有不同,我不会感到惊讶:

SET
    C.CALC_TIME_PERCENTAGE =
        (C.INDIV_CALC_DURATION_IN_S * 100.0 / V_TOTAL_CALC_TIME_IN_S)

但是您提到在某个日期的计算中有很多行,因此这可能是一个舍入误差。请尝试在两个字段(或至少在CALC_TIME_PERCENTAGE字段)中使用DOUBLE数据类型,看看与100%的差异是否会变小。
我不确定DB2是否有DECIMAL(x,y)数据类型,在这种情况下可能更合适。
另一个问题是如何求出CALC_TIME_PERCENTAGE的和。我想你(和其他人)会使用:

SELECT
            P_DATE, SUM(CALC_TIME_PERCENTAGE)
        FROM
            MY_SCHEMA.MY_CALC_DATA_TABLE C
        GROUP BY P_DATE

这样,你就无法确定求和的顺序,甚至无法确定,但你可以试试看:

SELECT
            P_DATE, SUM(CALC_TIME_PERCENTAGE)
        FROM
          ( SELECT
                P_DATE, CALC_TIME_PERCENTAGE
            FROM
                MY_SCHEMA.MY_CALC_DATA_TABLE C
            ORDER BY P_DATE
                   , CALC_TIME_PERCENTAGE ASC
          ) AS tmp
        GROUP BY P_DATE

优化器可能会忽略内部的ORDER BY,但值得一试。
造成这种巨大差异的另一种可能性是,在UPDATESHOW percent SUM操作之间从表中删除了行。
您可以通过运行计算(不使用UPDATE)并求和来测试是否会发生这种情况:

SELECT
            P_DATE
          , SUM( INDIV_CALC_DURATION_IN_S * 100.0 / T.TOTAL )                   
            AS PERCENT_SUM
        FROM
            MY_SCHEMA.MY_CALC_DATA_TABLE C
          , ( SELECT SUM(INDIV_CALC_DURATION_IN_S) AS TOTAL
              FROM MY_SCHEMA.MY_CALC_DATA_TABLE
            ) AS TMP
        GROUP BY P_DATE
sycxhyv7

sycxhyv72#

可能是舍入问题。请改用C.INDIV_CALC_DURATION_IN_S * 100 / V_TOTAL_CALC_TIME_IN_S

bfhwhh0e

bfhwhh0e3#

如果C.INDIV_CALC_DURATION_IN_S非常小,但您有大量的行(因此V_TOTAL_CALC_TIME_IN_S相比之下变得很大),则

(C.INDIV_CALC_DURATION_IN_S / V_TOTAL_CALC_TIME_IN_S) * 100

很可能会丢失精度,尤其是在使用FLOAT时。
如果是这种情况,则将计算(如其他地方所述)更改为

(C.INDIV_CALC_DURATION_IN_S * 100) / V_TOTAL_CALC_TIME_IN_S

我应该增加总数,虽然它可能不会让你一直到100%
如果是这种情况,并且很多测量都是一秒的很小一部分,我会考虑考虑这个过程之外的问题:时间可以用毫秒或微秒来记录吗?这两种方法都可以为您提供一些额外的有效数字空间。

相关问题