Hive中Floor函数精度计算问题

前言


公司数据库部分产品基于Hive进行开发,其中出现一个Bug。Oracle中表t1有个字段类型为decimal(38,0),当Hive这边执行了select Floor(col) from dblink,显示 Floor函数计算的精度太大。但是select Floor(col) from oracle_table 在Oracle这边本身就可以执行,而且Floor的意思是取小于等于的最大整数。

首先介绍一下精度问题:precision和scale

1.数据库中precesion和scale问题


(1)precision:表示有效数字(小数点左右总长度) ,如果没有指定precision的话,Oracle将使用38作为精度。
(2)scale:表示小数范围(小数点右边长度), scale默认设置为0.  如果为负数,Oracle将把该数字取舍到小数点左边的指定位数。
例如:decimal(3,1),表示范围为99.9 ~ -99.9。
(3)多种情况讨论:
(Mysql和Oracle一样, precision简称p,scale简称s )
  • 情况一:如果插入的数据小数点位数比s大,则对scale+1位置的小数进行四舍五入。当decimal(3,1)为1.15时,自动四舍五入为1.2.
  • 情况二:当一个数的整数部分的长度 > p-s 时,Oracle就会报错
  • 情况三:当s为负数时,Oracle就对小数点左边的s个数字进行舍入。
    • 当decimal(10,-1)为9555.151时,四舍五入至小数点左边第一位,结果为9560
    • 当decimal(10,-2)为9555.151时,四舍五入至小数点左边第二位,结果为9600
    • 当decimal(10,-3)为9555.151时,四舍五入至小数点左边第三位,结果为10000
    • 当decimal(10,-4)为9555.151时,四舍五入至小数点左边第四位,结果为10000
    • 当decimal(10,-5)为9555.151时,四舍五入至小数点左边第四位,结果为0。

2.Hive源码中FloorUDF函数


 Hive源码中的思路如下:

(1)首先在GenericUDFFloorCeilBase类中重新计算精度,precision=precision-scale+1

 (2)其次在HiveDecimalUtils类中实例化decimal时,会验证precision和scale是否合法

但是这里忽略了致命的问题,因为HiveDecimal.MAX_PRECISION=38,当我定义一个列col类型decimal(38,0),真实数据为1。那么执行select Floor(col) from hive_table,真实数据应该为1,但这里会报错。因为GenericUDFFloorCeilBase重新计算precision=38-0+1=39,在validateParameter中会判断39>HiveDecimal.MAX_PRECISION从而报错

 

3.修改思路


Floor的意思是取小于等于的最大整数
  • 如果scale>0,precision+1多了
  • 如果scale<0, precision+1多了
  • 如果scale=0. precision+1多了
  • 当precision=scale时, +1有用 。比如decimal(1,1)取值0.1,Floor正确结果为0, 但0本身就是要占用一位有效数字
  • 当precision<scale。比如decimal(2,3),inceptor这里做了判断创建表时precision不能小于scale
因此在GenericUDFFloorCeilBase ,我们只需要判断precision等于scale再决定+1.
precision=precision==scale?precision-scale+1:precision-scale

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值