问题:

select * from payments where status = 1 and payment_fee = 0.31

查询结果为空(可四数据库明明有一条数据满足条件的)

解决:

  • 使用format
select * from payments where status = 1 and  format(payment_fee,2) = format(0.31,2);
  • 使用concat
select * from payments where status = 1 and  concat(payment_fee, '') = '0.31'
  • 使用like
select * from payments where status = 1 and payment_fee like 0.31

原因深究:

大意:FLOAT和DOUBLE类型表示近似数字数据值。 MySQL对单精度值使用四个字节,对双精度值使用八个字节。

对于FLOAT,SQL标准允许在括号中的关键字FLOAT后面的位中指定精度(而不是指数的范围)的可选规范。 ;即FLOAT(p)。 MySQL还支持此可选的精度规范,但是FLOAT(p)中的精度值仅用于确定存储大小。从0到23的精度导致4字节单精度FLOAT列。从24到53的精度将导致8字节的双精度DOUBLE列。

MySQL允许使用非标准语法:FLOAT(M,D)或REAL(M,D)或DOUBLE PRECISION(M,D)。在此,(M,D)表示总共可以存储多达M位的值,其中D位可以在小数点后。例如,显示为FLOAT(7,4)的列看起来像-999.9999。 MySQL在存储值时执行四舍五入,因此,如果将999.00009插入FLOAT(7,4)列,则近似结果为999.0001。

由于浮点值是近似值而不是作为精确值存储的,因此在比较中尝试将它们视为精确值可能会导致问题。它们还受平台或实现依赖性的约束。有关更多信息,请参见第B.4.4.8节“浮点值的问题”

为了获得最大的可移植性,需要存储近似数值数据值的代码应使用FLOAT或DOUBLE PRECISION,而没有规定精度或位数。

以上大意: 使用基于语句的复制,值从十进制转换为二进制。由于十进制和二进制表示形式之间的转换可能是近似的,因此涉及浮点值的比较是不精确的。对于显式使用浮点值或隐式转换为浮点值的操作,这是正确的。由于计算机架构,用于构建MySQL的编译器等方面的差异,浮点值的比较可能在主服务器和从属服务器上产生不同的结果。

ps:
float类型不指定精度时,对float列的精确检索可能不正确。
使用float还会存在一个问题是insert时会存在数据丢失问题。
例如我insert一个字段为 131072.32 的值到数据库,成功之后实际到数据库的是 131072.31。。。少了0.01.。。。所以float大家还是要慎用

关于MySQL如何选择float, double, decimal可以参考这篇文章,通俗易懂:
http://blog.leanote.com/post/weibo-007/mysql_float_double_decimal