为何SQL中FLOAT类型转字符串后使用LIKE查询无效,转DECIMAL再转字符串却有效?
问题解析与解决办法
这事儿我碰到过好几次,核心问题就出在FLOAT是近似数值类型上——它不是用精确的十进制格式存储数据的,而是采用二进制浮点方式存储,这就导致转字符串的时候容易出“隐形”问题:哪怕你在SELECT列表里看到的转换结果是对的,到WHERE子句里做匹配时可能就掉链子了。
先拆解你的两个语句差异:
- 语句1直接将FLOAT转VARCHAR:
CONVERT(varchar(255), number)
虽然你查单行时看到转出来的是201608147,但FLOAT存储的其实是近似值(比如实际可能是201608146.999999976这种接近但不完全等于目标值的数)。在WHERE子句遍历全表时,有些行的转换结果可能偷偷变成科学计数法格式(比如2.01608147E+08),或者带了微小的精度尾巴,自然匹配不上%201608147%。 - 语句2先转DECIMAL再转VARCHAR:
CONVERT(varchar(255), CONVERT(decimal(20, 2), number))
DECIMAL是精确数值类型,转换时会把FLOAT的近似值四舍五入成精确的十进制数(你这里得到201608147.00),再转字符串就完全符合匹配要求了,所以能查到结果。
聊聊你那组验证查询
你跑的这条验证语句:
SELECT number, CONVERT(varchar(255), number), CONVERT(varchar(255), CONVERT(decimal(20, 2), number)) FROM [object]
返回的结果看起来直接转字符串是正确的,但为啥WHERE子句里不行?因为SELECT里看的是已经匹配到的那一行的转换结果(也就是刚好近似值转字符串后显示为201608147的行),但WHERE子句是对所有行做转换,那些存储近似值偏差稍大的行,直接转字符串就不是你要的格式了,所以整体返回0行。
给你几个实用的解决方向
- 从根源改字段类型:如果这个字段存储的是精确的整数或固定小数,赶紧把FLOAT改成DECIMAL或者INT,以后就不会再遇到这种糟心事了。
- 查询时先转精确类型:要是没法改字段类型,就像你语句2那样,先转成DECIMAL再转字符串匹配,稳得很。
- 优化查询性能:如果表数据量大,这种字段转换会让索引失效,查询速度变慢。可以整个计算列(自动存储转换后的字符串)并给计算列加索引;或者在插入/更新数据时同步维护一个字符串类型的字段,查询直接用这个字段匹配就行。
内容的提问来源于stack exchange,提问作者Lars Hendriks
相关产品推荐
相关产品推荐

