【发布时间】:2017-05-23 04:43:52
【问题描述】:
我对 BigQuery 和处理财务计算有一个真正的问题。根据查询,它似乎少了几分钱,这不符合我的需要。这是一个例子。考虑这个非常简单的数据集:
TOT_AMT,DLY_AMT,SUN_AMT,CREDIT_COPIES,UNIT_COST_DLY,UNIT_COST_SUNDAY,DAILY_COPIES,SUNDAY_COPIES 81.91,16.58,65.33,15,1.105,4.355,1,1 10.67,0.0,10.67,3,1.245,3.555,0,1 24.74,8.16,16.58,3,1.36,5.525,2,1 38.03,0.0,38.03,9,0.0,4.225,0,1
现在进行基本的舍入和测试不会太难,但不幸的是。我尝试了多种方法,如下所述。我只能关闭一个查询。这是要运行的查询:
SELECT
TOT_AMT,
ROUND(ROUND(UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES *10000)/10000 + ROUND(UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES * 10000)/10000,2) AS TOT_AMT_calc1,
ROUND( ( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES * 100 ) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES * 100 ) )/100, 2) AS TOT_AMT_calc2,
ROUND( ( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES ) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES ) ), 2) AS TOT_AMT_calc_FULL,
ROUND( ( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES *100) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES *100 ) ), 2) AS TOT_AMT_calc_FULL2,
( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES ) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES ) ) AS TOT_AMT_calc_FULL_NOROUND,
ROUND(ROUND( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES *1000) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES *1000) )/1000,2) AS TOT_AMT_calc_thousand,
ROUND(ROUND( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES *100) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES *100) )/100,2) AS TOT_AMT_calc_works
FROM
`my_project.my_table`
这个数据集的输出令人震惊:
TOT_AMT,TOT_AMT_calc1,TOT_AMT_calc2,TOT_AMT_calc_FULL,TOT_AMT_calc_FULL2,TOT_AMT_calc_FULL_NOROUND,TOT_AMT_calc_thousand,TOT_AMT_calc_works 81.91,81.9,81.9,81.9,8190.0,81.9,81.9,81.9 10.67,10.66,10.66,10.67,1066.5,10.6650000000000001,10.66,10.67 24.74,24.73,24.73,24.74,2473.5,24.7350000000000003,24.73,24.74 38.03,38.02,38.02,38.02,3802.5,38.025,38.02,38.03
如您所见,正确获得基本财务计算所期望的舍入的唯一方法是使用此功能:
ROUND(ROUND( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES *100) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES *100) )/100,2)
我需要一些东西来充分发挥作用,以确保对财务进行完美的计算。在 BigQuery 问题跟踪器上的这个问题中可以概述我想要超过 100 (10,000) 次的主要愿望: https://issuetracker.google.com/issues/35906014
唉,这也不管用,round 不再正常运行。
任何额外的见解将不胜感激。我需要一种可重复且准确的方法来计算真实的财务数据,而 BigQuery 轮次即使在小数字上也失败了。 UDF 会更好吗?
* 更新 * 通过将表转换为整数并导出表进行了一些额外的测试。首先基本上乘以 100,第二次乘以 10000。BigQuery 似乎将 Integer 存储为具有类似舍入问题的 int64。对于所有整数都乘以 10,000 的表格,我能得到准确结果的唯一方法与 float64 中的方法基本相同。即在浮点值乘以 100 处舍入。
SELECT
TOT_AMT,
ROUND((( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES) )/10000 ),2) AS TOT_AMT_calc_fail1,
((( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES) )/10000 )) AS TOT_AMT_calc_fail2,
(ROUND(( ( UNIT_COST_DLY * DAILY_COPIES * CREDIT_COPIES) + ( UNIT_COST_SUNDAY * SUNDAY_COPIES * CREDIT_COPIES) )/100 )/100) AS TOT_AMT_calc_works3
FROM
`my_project.my_table`
我什至尝试重新施法,但没有任何影响。转换回 float 似乎没有任何作用,因为它看起来 INT64 的反应与 FLOAT64 相同。
【问题讨论】:
-
旁注,即使是 excel 也有舍入问题。尽管有舍入误差,但通过下面的答案,我能够正确获得正确的值。
标签: google-bigquery user-defined-functions udf