数据库 数据库中小数的字段类型慎用 float

samport · 2018年11月28日 · 最后由 sevk 回复于 2018年11月30日 · 696 次阅读

最近在项目中碰到一个奇怪的现象:商品表中明明有价格为72.05元的商品,用"价格等于72.05"的条件却检索不出来。

Product.where(price: 72.05).first

但是如果用区间条件的话,是能检索出来该商品的:

Product.where("price > ?", 72).where("price < ?", 73)

开始以为是ruby程序的问题,后来直接在mysql命令行下用sql语句去检索,问题一样存在,看来是数据库本身的问题。

反复检查以后,发现价格字段类型是float类型。使用alter的语句将价格字段修改成decimal (总位数,小数点后位数),问题得到了解决。

-- SQL 语句:
ALTER TABLE products MODIFY COLUMN price decimal(10,2);

当然,在rails项目里,按照流程还是必须创建和执行如下的migration的。不过不知道为什么这个操作并不能反映到mysql上,所以只能额外手工执行上面的mysql操作。

class ChangePirce < ActiveRecord::Migration[5.2]
  def change
      change_column : products, :price, :decimal, :precision => 10, :scale => 2
  end
end

关于float与decimal类型的区别,看起来不起眼,但是不注意的话会掉到这样的坑里去。这次的经验让我明白,以后跟金额相关的字段,统统明确用decimal类型。

共收到 10 条回复

跟钱有关的用decimal 不是常识么

protip: 存decimal,app端比较用to_d

关键字:浮点数、IEEE 754

确实跟自己经验不足有关。这种问题最坑人的是程序不会报错,只能在通过测试甚至上线后才能发现失误。

整数 + 币种可解决问题,也能解决多币种问题

钱,应该用整数

用 PG 就没这个问题,直接用 money 类型

确实是个坑,比较反直觉。 感谢分享 :)

整数+千分比

单精度浮点数的有效位数是7位。 双精度浮点数的有效位数是16位。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册