首页 > 数据库    日期:2026-08-19 / 浏览

前言

遇到一个比较奇葩的需求,数据表有两个字段类型都是number(18,6),A字段存储的是未经处理的数字,比如0.233350这样的;B字段存储的是由程序经过四舍五入后的数字,比如0.233000。实际上用户输入的数据得出的结果确实是0.233350。

因为业务的需要,当比对两个字段的值有差异时,系统会认为有异常。

程序是第三方公司写的,改不了代码,那就只能从数据库开始着手了。

根据小数的特点,有以下几个思路

思路一、判断小数部分有效长度

比如0.233000的小数部分有效长度是3;0.233300的小数部分有效长度是4。

特殊情况,当数字是一个整数时,比如 100.000000的小数部分有效长度是0。

那么我们来构造一下SQL语句

分别以数字999.233000、999.233300以及999.000000来举例

select 999.233000 fNumber,
       case when instr(to_char(999.233000),'.')=0 then 0
       else 
       length(substr(to_char(999.233000),instr(to_char(999.233000),'.')+1,length(to_char(999.233000))-instr(to_char(999.233000),'.'))) 
       end fLength
from dual

999.233000得到的结果是

999.233300得到的结果是

999.000000得到的结果是

这个结果是符合预期的。

这种思路的判断条件是数位是否超过3,超过3的表示有3位以上的数位。

思路二、不判断有效数位,利用字符串的特性判断最后三位是否等于000

注意:这个思路是有前提的,只适用于特定精度情况下。

如果直接把小数用to_char函数转成字符串,会自动把后面的0去掉;

那么如何判断呢?首先根据字段类型可以知道,精度是6位小数,那么只需要把小数转成整数即可使用to_char函数转字符串,而不会丢失精度。

同样以数字999.233000、999.233300以及999.000000来举例

select 999.233000 fNumber,to_char(999.233000*1000000) fmultiNumber,substr(to_char(999.233000*1000000),-3,3) fLast3Char from dual

999.233000得到的结果是

999.233300得到的结果是

999.000000得到的结果是

同样地,结果也是符合预期的。

这种思路的判断条件是FLAST3CHAR是否等于000。

需要注意的是这种思路中,相乘的那个基数是受字段的精度影响的,比如如果字段是number(18,3)的话,那么就要乘以1000。

思路三、将小数转换成整数,再除以1000,判断结果是否为小数

这是在思路二的基础上发展而来,思路二中字段乘以1000000后会变成一个整数,如果进一步再除以1000的话,判断结果是否为小数就能解决问题。

同样以数字999.233000、999.233300以及999.000000来举例 

select 999.233000 fNumber,to_char(999.233000*1000000/1000) fmultiNumber,
       instr(to_char(999.233000*1000000/1000),'.') fPointIndex
from dual

999.233000得到的结果是

999.233300得到的结果是

999.000000得到的结果是

同样结果也是符合预期的。

这种思路只需要判断FPOINTINDEX是否大于0就可以。

与思路二一样,这种思路中,相乘的那个基数也是受字段的精度影响的,比如如果字段是number(18,3)的话,那么就要乘以1000。

而除法的基数,则是根据小数后要保留多少个0来决定,比如要保留2个0,则除以100

总结

觉得上面的内容有用吗?快来点个赞吧!

点赞() 我要打赏

温馨提示 : 本站内容来自会员投稿以及互联网,所有源码及教程均为作者总结编辑,请大家在使用过程中提前做好备份,以免发生无法预知的错误,源码类教程请勿直接用于生产环境!

 可能感兴趣的文章