【问题标题】:Sum of table attributes when value is string值为字符串时的表属性总和
【发布时间】:2017-02-02 18:40:40
【问题描述】:

我以前从未遇到过这种情况。我正在使用一个表属性,其值是一个字符串,而不是浮点数/整数。

Model.first.amount => "58.00"

我需要总结所有金额。我习惯了,amount 是一个浮点数,会是:

Model.all.sum(&:amount) => # total value

大胆猜测:

Model.all.sum(&:amount.to_i) # undefined method `to_i' for :amount:Symbol

有没有一种简洁的方法来总结金额?还是把数据库转成float

【问题讨论】:

  • 你需要做强制转换为 SELECT CAST('1234' AS FLOAT)。
  • 您不应该使用浮点数来表示货币金额。
  • 我知道。我正在使用某人的数据库。他们不会听信改变它。
  • 不,我的意思是:您不应该将字符串值转换为浮点数。使用可以处理精确存储的类型,例如 Ruby 中的 BigDecimal 或 SQL 中的 DECIMAL
  • 啊!感谢那。比如amount.to_d?

标签: ruby-on-rails ruby postgresql ruby-on-rails-5


【解决方案1】:

使用 Ruby 处理数据库内存效率低。

第一枪:

Model
  .pluck(:amount) # will fire sql
  .sum(&:to_f)    # convert to float, operating on resulting Array, not AR and sum

但处理数据库数据最有效的方式当然是 SQL:

Model.sum("CAST(COALESCE(amount, '0') AS DECIMAL)")
  1. coalesce 将用'0' 替换空值
  2. sum 所有值都转换为 DECIMAL

【讨论】:

  • IIRC,您必须指定精度,例如DECIMAL(10,2)
  • @Stefan AFAIR 指定精度是可选的
【解决方案2】:

在纯 Ruby 中,您可以使用方法 inject

Model.all.inject(0) { |sum, object| sum += object.amount.to_i }

【讨论】:

  • 坏主意,如果有很多对象,这种方法会导致内存过载。
  • 而且数据是十进制的(或者白痴做的浮点存储)——不是整数。
【解决方案3】:

我没有评论权限,但这应该适用于 ruby​​:

Model.all.map(&:to_f).reduce(&:+)

【讨论】:

  • 这行不通,因为您必须对数量属性的值而不是对象本身求和。 Model.all.map(&:amount).map(&:to_f).reduce(&:+)
猜你喜欢
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
  • 2015-07-09
相关资源
最近更新 更多