我遇到了无法解释Redshift如何处理SUM划分的情况。
有示例表:
create table public.datatype_test(
a numeric(19,6),
b numeric(19,6));
insert into public.datatype_test values(222222.2222, 333333.3333);
insert into public.datatype_test values(444444.4444, 666666.6666);
现在,我尝试运行查询:
select sum(a)/sum(b) from public.datatype_test;
我得到结果0.6666(小数点后4位)。它与工具显示无关,它实际上仅返回小数点后四位,并且表中的数字大小无关紧要。在我的情况下,小数点后4位不够精确。 如果我使用AVG代替SUM,也是如此。
如果我使用MAX而不是SUM,我将得到:0.6666666666666666666(19个小数)。
当不使用物理表时,它还会返回正确的结果(0.6666666666666667):
with t as (
select 222222.2222::numeric(19,6) as a, 333333.3333::numeric(19,6) as b union all
select 444444.4444::numeric(19,6) as a, 666666.6666::numeric(19,6) as b
)
select sum(a)/sum(b) as d from t;
我查看了有关SUM和Computations with Numeric Values的Redshift文档,但是根据文档,我仍然没有得到结果。
对表列使用浮点数据类型不是一种选择,因为我需要存储精确的货币金额,而15个有效数字是不够的。
在SUM聚合上使用强制类型转换也可以得到0.6666666666666666666(19位小数)。
select sum(a)::numeric(19,6)/sum(b) from public.datatype_test;
但是它看起来错了,我不能强迫BI工具执行此替代方法,使用此数据的每个人也不应使用这种替代方法。
我已经尝试在PostgreSQL 10中使用相同的测试,并且该测试可以正常工作,返回足够的小数位数进行除法。
我可以使用数据库设置来避免在SQL查询中进行强制转换吗? 任何建议或指导都将受到高度赞赏。
Redshift版本: i686-pc-linux-gnu上的PostgreSQL 8.0.2,由GCC gcc(GCC)3.4.2 20041017(Red Hat 3.4.2-6.fc3),Redshift 1.0.4081编译 使用dc2.8xlarge节点
答案 0 :(得分:0)
我遇到了类似的问题,尽管我没有不需要解决方法的解决方案,但至少可以解释一下。
除法结果的精度/小数位数由“带数值的计算”文档中的规则定义。
这些规则的结果是将decimal(19,6)
除以另一个decimal(19,6)
将返回decimal(38,19)
。
不过,您正在发生的事情是MAX
返回与基础列相同的精度/小数位数,但是SUM
无论如何返回decimal(38,*)
。
(这可能是一项安全预防措施,可防止“大数据”总和上溢)。如果将decimal(38,6)
除以decimal(38,4)
。
AWS支持人员可能不会认为这是一个缺陷-没有关于如何处理除法小数精度的SQL标准,并且鉴于这是有据可查的行为,因此可能是一个有意的决定。
解决此问题的唯一方法是强制转换分子,或将其乘以sum(a) * cast(1 as decimal(10,9))
之类的可移植SQL,并将在分子中强制使用小数点,从而对结果进行强制。
为方便起见,我在JSFiddle with the rules中制作了一个计算器,以便您可以使用不同的选项:
scale = Math.max(4, s1 + p2 - s2 + 1)
precision = p1 - s1 + s2 + scale
if (precision > 38) {
scale = Math.max((38 + scale - precision), 4)
precision = 38
}