SQLServer:避免舍入错误
我需要有关 SQL Server 中浮点数学的帮助。下面给出了问题的简化版本
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
我想要的是将比例和成本分配四舍五入到小数点后三位,但它们分别加起来为 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