5

我有一个售价 4 欧元的产品,我需要将这笔钱分配给 3 个部门。在第二列中,我需要获取该产品的行数并除以部门数。

我的查询:

select
   department, totalvalue,
   (totalvalue / (select count(*) from departments d2 where d2.department = p.product))
       dividedvalue
from products p, departments d
where d.department = p.department

Department  Total Value  Divided Value
----------  -----------  -------------
A           4            1.3333333
B           4            1.3333333
C           4            1.3333333

但是当我对这些值求和时,我得到 3,999999。当然有数百行我有很大的不同......有没有机会定义2个十进制数字并舍入最后一个值?(我的结果是 1.33 1.33 1.34)我的意思是,有什么方法可以调整最后一行?

4

5 回答 5

1

为了处理这个问题,对于每一行,您必须执行以下操作:

  • 执行分区
  • 将结果四舍五入到适当的美分数
  • 将取整后的金额与除法运算结果的差值相加
  • 当差的总和超过最低小数位(在本例中为 0.01)时,将该数量添加到下一次除法运算的结果中(四舍五入后)。

这将在各行中平均分配小数。不幸的是,在 SQL 中没有简单的方法通过简单的查询来做到这一点。在过程代码中执行此操作可能会更好。

至于它有多重要,对于金融应用和机构来说,这样的事情是非常重要的,即使它只是一分钱,即使它只能每X条记录发生一次;通常,用户希望看到与便士(或任何您的货币单位)完全相关的值。

最重要的是,您不希望出现像“超人 III”“办公空间”这样的漏洞。

于 2011-01-24T18:34:06.817 回答
0

也许您可以制作第四行,即 Total - sum(A,B,C)。但这取决于你想做什么,如果你需要精确的值,你可以保留分数,否则,截断并且不关心虚拟损失

于 2011-01-24T17:19:11.270 回答
0

精确到小数点后六位,如果您将最终数字四舍五入到小数点后两位,您将需要大约 5,000 笔交易才能注意到 1 美分的差异。将小数位数增加到可接受的水平将消除大多数问题,即使用 9 位小数,您需要大约 5,000,000 次交易才能注意到一分钱的差异。

于 2011-01-24T17:23:27.053 回答
0

也可以简单地通过将特定值的舍入差异添加到要舍入的下一个数字(舍入之前)来完成。这样,堆总是保持相同的大小。

于 2015-01-29T08:28:46.623 回答
0

这是Martin提供的算法的 TSQL (Microsoft SQL Server) 实现:

-- Set parameters.
DECLARE @departments INTEGER = 3;
DECLARE @totalvalue DECIMAL(19, 7) = 4.0;

WITH
CTE1 AS
(
    -- Create the data upon which to perform the calculation.
    SELECT

        1 AS Department
        , @totalvalue AS [Total Value]
        , CAST(@totalvalue / @departments AS DECIMAL(19, 7)) AS [Divided Value]
        , CAST(ROUND(@totalvalue / @departments, 2) AS DECIMAL(19, 7)) AS [Rounded Value]

    UNION ALL

    SELECT

        CTE1.Department + 1
        , CTE1.[Total Value]
        , CTE1.[Divided Value]
        , CTE1.[Rounded Value]

    FROM

        CTE1

    WHERE

        Department < @departments
),

CTE2 AS
(
    -- Perform the calculation for each row.
    SELECT

        Department
        , [Total Value]
        , [Divided Value]
        , [Rounded Value]
        , CAST([Divided Value] - [Rounded Value] AS DECIMAL(19, 7)) AS [Rounding Difference]
        , [Rounded Value] AS [Calculated Value]

    FROM

        CTE1

    WHERE

        Department = 1

    UNION ALL

    SELECT

        CTE1.Department
        , CTE1.[Total Value]
        , CTE1.[Divided Value]
        , CTE1.[Rounded Value]
        , CAST(CTE1.[Divided Value] + CTE2.[Rounding Difference] - ROUND(CTE1.[Divided Value] + CTE2.[Rounding Difference], 2) AS DECIMAL(19, 7))
        , CAST(ROUND(CTE1.[Divided Value] + CTE2.[Rounding Difference], 2) AS DECIMAL(19, 7))

    FROM

        CTE2

            INNER JOIN CTE1
                ON CTE1.Department = CTE2.Department + 1

)

-- Display the results with totals.
SELECT 

    Department
    , [Total Value]
    , [Divided Value]
    , [Rounded Value]
    , [Rounding Difference]
    , [Calculated Value]

FROM 

    CTE2

UNION ALL

SELECT

    NULL
    , NULL
    , SUM([Divided Value])
    , SUM([Rounded Value])
    , NULL
    , SUM([Calculated Value])

FROM

    CTE2

;

输出:

在此处输入图像描述

您可以在顶部插入您想要的任何数字。我不确定这个算法是否有数学证明。

于 2019-08-08T15:06:36.530 回答