SQL 服务器:避免舍入错误

SQL Server: Avoiding Rounding Errors

我需要 SQL 服务器中的浮点数学方面的帮助。下面给出问题的简化版本

DECLARE @TOTALCOST NUMERIC(18, 4) = 1.125;

WITH CTE AS (
    SELECT item='Item1', volume=3.636
    UNION
    SELECT item='Item2', volume=14.946
    UNION
    SELECT item='Item3', volume=26.05
)
SELECT
    item,
    volume,
    totVol = (SUM(volume) OVER (PARTITION BY NULL)),
    proportion =  (SUM(volume) OVER (PARTITION BY item)) / (SUM(volume) OVER (PARTITION BY NULL)),
    costAllocation = (SUM(volume) OVER (PARTITION BY item)) * @TOTALCOST / (SUM(volume) OVER (PARTITION BY NULL))
FROM CTE
ITEM    Volume  totVol  Proportion  costAllocation
==========================================
Item1   3.636   44.632  0.081466    0.091649
Item2   14.946  44.632  0.334871    0.376730
Item3   26.050  44.632  0.583661    0.656619

基本上比例就是item1的体积占三个item总体积的比例,然后1.125除以这个比例。 那是针对 item1 比例 = 3.636 / 44.632 成本分配 = 3.636 * 1.125 / 44.632

我想要的是四舍五入的比例和costAllocation只保留小数点后三位,但是它们相加正好分别是1和1.125。

我曾尝试将 Round() 函数置于各种排列中,但不知何故,我无法准确计算出如何按比例划分,以便它恰好加起来为 1 和 1.125。我不介意一个数字的最后一位小数是否有错误。比如1可以平均分成3份=0.333___每份,所以即使我们用普通的舍入函数分到3份还是会显示为0.333,3次求和也只会是0.999

所以我可以将比例报告为 0.333、0.333 和 0.334,这样它加起来正好是 1。

您要处理的不是浮点数数学,而是由于四舍五入而缺乏小数精度。

我实施的一个解决方案(主要是在报告中)是做类似下面的事情,在其中计算由于舍入而产生的差异并将其添加到一行(通常是最大值以最小化影响)。

declare @TOTALCOST numeric(18, 4) = 1.125;

with CTE as (
    select item='Item1', volume=3.636
    union
    select item='Item2', volume=14.946
    union
    select item='Item3', volume=26.05
), cte2 as (
select
    item,
    volume,
    totVol = (Sum(volume) over ()),
    proportion =  Round((Sum(volume) over (partition by item)) / (Sum(volume) over ()),3),
    costAllocation = Round((Sum(volume) over (partition by item)) * @TOTALCOST / (Sum(volume) over ()),3),
    Row_Number() over(order by volume desc) rn
from CTE
)
select item, volume, totVol, proportion, 
    costAllocation + case when rn=1 then @TOTALCOST-Sum(costAllocation) over() else 0 end costAllocation
from cte2