问题描述
我有一个销售税值,我需要将其平均分配到 3 个项目中。
例如:$153.88/3 = 51.29333333333333
四舍五入到小数点后两位表示货币时,it = $51.29
。
但是 $51.29*3=$153.87
比总税额低 1 美分。
是否有一个函数可以解决这些舍入误差,以便各个值总和总和?那么额外的 1 美分会随机分配给 1/3 的物品吗?
select '1' as item_number,153.88 as sales_tax,round(153.88 /3,2) as rounded
union all
select '2' as item_number,2) as rounded
union all
select '3' as item_number,2) as rounded
解决方法
考虑以下
select * except(pre_split,pos),round(if(pos > round(100 * (sales_tax - sum(pre_split) over()),2),pre_split,pre_split + .01),2) final_split
from (
select *,round(sales_tax / count(1) over(),2) pre_split,row_number() over(order by rand()) pos
from `project.dataset.table`
)
如果适用于您问题中的样本数据 - 输出为
下一次运行输出
下一次运行...
所以,正如你所看到的 - 额外的分是随机应用的 - 与 rand() 函数的运行一样随机 :o))
此外,如果超过一美分 - 所有美分也将均匀随机地应用
,这是一个棘手的问题。使用 floor()
、ceil()
或 round()
获得近似解决方案非常简单。然后,您甚至可以将“额外”添加到其中一行。
然而,额外的可能超过 0.01,这开始看起来很尴尬。当您拥有三个项目时不会发生这种情况,但可能会发生更多。我更喜欢将它们均匀地分布在行上。
所以,我建议:
with t as (
select '1' as item_number,153.89 as sales_tax
union all
select '2' as item_number,153.89 as sales_tax
union all
select '3' as item_number,153.89 as sales_tax
union all
select '4' as item_number,153.89 as sales_tax
union all
select '5' as item_number,153.89 as sales_tax
union all
select '6' as item_number,153.89 as sales_tax
union all
select '7' as item_number,153.89 as sales_tax
)
select t.*,(floor(sales_tax * 100 / count(*) over ()) +
(case when floor(sales_tax * 100 / count(*) over ()) * count(*) over () +
row_number() over () - 1 < sales_tax * 100
then 1 else 0
end)
) / 100.0
from t;
我已经包含了一个示例,其中分布会产生影响。