计算ActiveRecord nil属性

时间:2017-10-01 13:02:21

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

在我的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_beforeprice_after设为nil。这并不理想,因为我想添加两列并将其命名为price。如何在不多次访问数据库的情况下实现这一目标?

2 个答案:

答案 0 :(得分:4)

您可以使用NULL确保将COALESCE值计算为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_before,默认情况下将price_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')

答案 1 :(得分:1)

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

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

我怀疑你之后是什么,因为你的查询中没有group。如果你是一笔钱,那么@ulferts的答案是正确的。