Spark SQL中cast(decimal(38,16))小数位数保留异常问题求助
问题解决:Spark SQL中AVG结果转Decimal丢失小数位的问题
问题根源
原代码中365.25/12属于Double类型浮点运算,导致CASE表达式的返回值为Double。Spark的AVG函数对Double类型计算后,返回结果仍为Double——而Double的有效精度限制(约15-17位有效数字)会导致你的场景中计算结果仅保留10位有效小数,后续转Decimal(38,16)时只能用零填充剩余位数。
当移除除法操作时,datediff返回整数,CASE表达式结果为整数,AVG会自动切换为高精度Decimal类型计算,因此转Decimal(38,16)能保留完整小数位。
解决方案
将所有参与运算的常量转换为Decimal类型,确保整个计算流程在Decimal精度下执行,避免Double类型的精度丢失。
修改后代码示例(推荐用精确常量)
因为365.25/12 = 30.4375是精确值,直接使用该Decimal常量可以简化计算并保证精度:
cast( AVG( CASE WHEN a.is_debtor = 1 AND a.is_kk = 0 AND a.is_open = 0 THEN CAST(datediff((a.date_end_plan + interval '1 day'), a.date_start) AS DECIMAL(38,16)) / CAST(30.4375 AS DECIMAL(38,16)) END ) as decimal(38,16) ) AS avg_term_plan_closed
保留原式结构的修改
如果需要保留原式的除法逻辑,将所有常量转为Decimal即可:
cast( AVG( CASE WHEN a.is_debtor = 1 AND a.is_kk = 0 AND a.is_open = 0 THEN CAST(datediff((a.date_end_plan + interval '1 day'), a.date_start) AS DECIMAL(38,16)) / (CAST(365.25 AS DECIMAL(38,16)) / CAST(12 AS DECIMAL(38,16))) END ) as decimal(38,16) ) AS avg_term_plan_closed
验证逻辑
修改后,CASE内的所有运算都在Decimal(38,16)精度下执行,AVG函数会基于Decimal类型计算平均值,最终转换后的结果就能保留完整的16位小数,与期望输出一致。
内容的提问来源于stack exchange,提问作者Егор Бугаков
相关产品推荐
相关产品推荐

