我记得那阵子,我们组里接了个新需求,要做一个库存报表。里头有个数据是关于“实际入库批次”的统计,要求必须是整数,哪怕入库了半个批次,也得按没到整批算。我当时想,这不就是向下取整吗?简单!
本站为89游戏官网游戏攻略分站,89游戏每日更新热门游戏,下载请前往主站地址:www.gm89.icu
我当时信心满满地打开SQL Developer,想着随便一个函数就能搞定。结果一动手,才发现Oracle里向下取整的门道还不少。我最先想到的就是FLOOR。
初识FLOOR,感觉对了
我随便写了几条SQL来测试FLOOR这个函数。比如:
SELECT FLOOR(10.8) FROM DUAL;结果是 10。SELECT FLOOR(10.2) FROM DUAL;结果是 10。SELECT FLOOR(-10.8) FROM DUAL;结果是 -11。SELECT FLOOR(-10.2) FROM DUAL;结果是 -11。
我当时就琢磨,这FLOOR函数挺实在的,就是往数轴的负无穷方向靠拢。正数小数部分直接抹掉,负数则是往更小的负数方向去。这个跟我们常见的数学意义上的向下取整是一致的。我心想这下稳了,报表数据肯定能对得上。
遇到TRUNC,开始犯迷糊
正当我准备把FLOOR应用到正式SQL里的时候,同事老王过来了。他看了看我的SQL,笑了笑说:“你这个需求,用TRUNC也行,但跟FLOOR有点区别,你得注意点。”
我当时就懵了,TRUNC?这不是截断函数吗?还能用来向下取整?好奇心驱使下,我又跑了几条测试:
SELECT TRUNC(10.8) FROM DUAL;结果是 10。SELECT TRUNC(10.2) FROM DUAL;结果是 10。SELECT TRUNC(-10.8) FROM DUAL;结果是 -10。SELECT TRUNC(-10.2) FROM DUAL;结果是 -10。
我一看结果,傻眼了。正数的时候,FLOOR和TRUNC表现一样,都是直接把小数部分干掉。但一到负数,它们就分家了!FLOOR(-10.8)是-11,但TRUNC(-10.8)却是-10。这差别可大了去了!
老王看我一脸疑惑,就给我解释说,TRUNC就是简单粗暴地把小数部分“截断”掉,不管正负都往0的方向靠近。而FLOOR则是往负无穷方向取整,也就是我们常说的“地板函数”。对于正数,往负无穷取整和往0取整没区别;但对于负数,往负无穷取整就会取到更小的负数,而往0取整就是取到更大的负数(或者说,绝对值更小的负数)。
听他这么一说,我才恍然大悟。原来向下取整,还有“数学意义上的向下取整”和“简单截断取整”这两种不同的理解。我们报表的需求,是严格意义上的“向下取整”,也就是FLOOR更符合。如果一个批次算10个,来了10.8个,那报表上只能算10个完整批次。如果是-10.8个,那意味着欠了11个,而不是欠了10个。这个细微的差别,在实际业务里可能导致截然不同的结果。
顺便看了一眼ROUND(X, 0)
我还顺便问了老王,那ROUND(X, 0)这种取整方式,是不是也算向下取整的一种?
老王说,ROUND(X, 0)是四舍五入到整数位。它可不是向下取整,有时候会往上走,有时候会往下走。比如:
SELECT ROUND(10.8, 0) FROM DUAL;结果是 11。SELECT ROUND(10.2, 0) FROM DUAL;结果是 10。SELECT ROUND(-10.8, 0) FROM DUAL;结果是 -11。SELECT ROUND(-10.2, 0) FROM DUAL;结果是 -10。
我一看,果然,ROUND是看小数部分是不是大于等于0.5来决定是向上还是向下。所以它不是固定的向下取整。除非你的业务需求就是四舍五入,否则不能乱用。不过老王也提了一嘴,如果你用TRUNC(X, -N)或者ROUND(X, -N)这种,倒是可以实现对十位、百位这种位数进行向下或四舍五入取整。但那又是另一个话题了,跟我们今天的向下取整到个位不是一回事。
我的实践经验总结
经过这回“踩坑”和老王的指点,我算是彻底明白了Oracle里向下取整的这些门道。对于我们这种需要严格按照数学定义“向负无穷方向取整”的业务场景,FLOOR是首选,它最符合直觉。而如果只是单纯想把小数部分抹掉,不考虑正负数的差异,往0方向截断,那TRUNC也是个好选择。但你得清楚这两者对于负数的不同表现。至于ROUND(X, 0)这种,它是四舍五入,并不是固定向下取整,虽然有时候结果一样,但不能混为一谈。
所以说,以后碰到“向下取整”的需求,我都会先问自己一句:这是要严格数学意义上的向下取整(Floor),还是简单粗暴地截断小数部分(Trunc)?把这个想清楚了,选对函数就没问题了。这回报表我就用了FLOOR,数据出来一分不差,老总看了也满意。看来,学技术真的得多问多实践,光凭想当然可不行。