Redshift数值精度截断

时间:2018-10-01 13:42:15

标签: sql amazon-redshift

我遇到了无法解释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; 

我查看了有关SUMComputations 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节点

1 个答案:

答案 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
}