【问题标题】:Computing ActiveRecord nil attributes计算 ActiveRecord nil 属性
【发布时间】:2017-10-01 13:02:21
【问题描述】:

在我的 Rails 应用程序中,其中一个模型中有类似的东西

def self.calc
  columns_to_sum = "sum(price_before + price_after) as price"
  where('product.created_at >= ?', 1.month.ago.beginning_of_day).select(columns_to_sum)
end

对于某些行,我们将price_before 和或price_after 设置为nil。这并不理想,因为我想添加两列并将其命名为price。如何在不多次访问数据库的情况下实现这一目标?

【问题讨论】:

标签: ruby-on-rails ruby activerecord rails-activerecord


【解决方案1】:

您可以使用 COALESCE 确保将 NULL 值计算为 0,这将返回第一个非 NULL 值:

columns_to_sum = "sum(COALESCE(price_before, 0) + COALESCE(price_after, 0)) as price"

然而,这将计算所有产品的总价格。

另一方面,如果您只想用一种简单的方法来计算一种产品的价格,那么您可能不必这样做。然后你可以在Product 模型中添加一个方法

def.price
  price_before.to_i + price_after.to_i
end

这样做的好处是能够反映价格的变化(通过 price_before 或 price_after),而无需再次通过数据库,因为默认情况下将获取 price_beforeprice_after

但是如果你想例如根据将该功能放入数据库所需的价格从数据库中选择记录。

为此,我会调整您的范围并稍后再次加入:

def self.with_price
  columns_to_sum = "(COALESCE(price_before, 0) + COALESCE(price_after, 0)) as price"

  select(column_names, columns_to_sum)
end

这将使用额外的price 读取器方法返回所有记录。

还有一个独立于之前的范围:

def self.one_month_ago
  where('product.created_at >= ?', 1.month.ago.beginning_of_day)
end

然后可以这样使用:

Product.with_price.one_month_ago

这允许您在访问数据库之前继续修改范围,例如获取价格高于 x 的所有产品

Product.with_price.one_month_ago.where('price > 5')

【讨论】:

    【解决方案2】:

    如果您尝试获取每个单独记录的 price_before 和 price_after 的总和(而不是整个查询结果的单个总和),您希望这样做:

    columns_to_sum = "(coalesce(price_before, 0) + coalesce(price_after, 0)) as price"
    

    我怀疑这就是您所追求的,因为您的查询中没有 group。如果您是单次求和,那么@ulferts 的答案是正确的。

    【讨论】:

      猜你喜欢
      • 2017-09-17
      • 1970-01-01
      • 2015-11-27
      • 1970-01-01
      • 2013-07-04
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多