如何使用SQL查询ARTICLE表中price列小数位超过3位的记录?
原SQL的核心问题
你之前写的length(TO_CHAR(price)) > 7根本没法实现需求,两个硬伤:
- 转换结果不可控:直接对number值用不带格式的
TO_CHAR,转出来的字符串会被会话的NLS规则影响,可能带千分位逗号、货币符号、前后填充空格,甚至变成科学计数法,长度数值完全没有参考性。 - 判断逻辑完全错位:字符串总长度算的是“整数位+小数点+小数位”的总长度,既可能把没有任何小数的7位整数(比如1234567)误判成符合条件,又会把整数部分短、但小数超3位的值(比如1.2345,总字符串长度才6)漏掉,准确率极低。
正确实现方案
方案1:纯数值计算判断(推荐,性能更好)
绕开字符串转换的格式干扰,直接通过数值运算判断小数位数:把price和它的整数截断值做差,得到纯小数部分,乘以1000之后如果结果不是整数,就说明小数位数超过了3位。
SELECT name, price FROM ARTICLE WHERE (price - TRUNC(price)) * POWER(10, 3) <> TRUNC((price - TRUNC(price)) * POWER(10, 3));
- 实际校验:price=12.9584时,TRUNC截断得整数部分12,差值0.9584乘1000是958.4,和它的整数截断值958不相等,会被正常筛选出来;price=12.345时,差值乘1000刚好是整数345,会被正确排除。
- 优点:不受数据库会话格式设置影响,计算效率高,大表场景下也能快速完成过滤。
方案2:标准化字符串拆分判断(逻辑更直观)
如果习惯按字符串拆分的方式判断,一定要给TO_CHAR指定固定格式,杜绝默认转换的多余字符:用TM9格式模板可以把数字转成最精简的纯字符串(无千分位、无货币符号、无多余空格),再精准计算小数点后的位数。
SELECT name, price FROM ARTICLE WHERE INSTR(TO_CHAR(price, 'TM9'), '.') > 0 -- 先排除没有小数的纯整数 AND LENGTH(TO_CHAR(price, 'TM9')) - INSTR(TO_CHAR(price, 'TM9'), '.') > 3;
- 校验例子:price=45.874521转成字符串是
45.874521,小数点位置在第3位,字符串总长度9,9-3=6>3,符合筛选要求;整数100转成字符串是100,找不到小数点,第一个判断条件不满足,直接被过滤。
内容的提问来源于stack exchange,提问作者Abenamor
相关产品推荐
相关产品推荐

