ActiveRecord:在计算中将 nil 视为 0?

Slo*_*boy 3 ruby activerecord ruby-on-rails ruby-on-rails-4 ruby-on-rails-5

paper_weight我在控制器中使用此代码来访问分类中所有用户的平均值Heavy

if User.where(industry_type: 'Heavy')
 .joins(:papers)
 .where(papers: { paper_type: 'Officepaper' } )
 .pluck('avg(paper_weight)').first.nil?
 @heavy_indust_officepaper == 0
else
@heavy_indust_officepaper = User.where(industry_type: 'Heavy')
 .joins(:papers)
 .where(papers: { paper_type: 'Officepaper' } )
 .pluck('avg(paper_weight)').first * 3 
end
Run Code Online (Sandbox Code Playgroud)

然后该变量@heavy_indust_officepaper将显示在视图中。

nil问题在于,当一个或多个用户在 中输入条目时,上面的这段代码似乎无法正确计算平均值paper_type: 'Officepaper'

我知道这一点是因为我有两个用户,其中industry_type: 'Heavy' 一个有一个条目,其中paper_type: 'Officepaper'的条目是十进制 30。另一个用户有nil条目paper_type: 'Officepaper'

根据我的理解计算应该是30 + 0 / 2(users) = 15

然后15乘以3它应该给出45

但是变量@heavy_indust_officepaper显示90在视图中......这必须是以下结果30 * 3

有没有办法将上面代码中的 转换为 with nil???0

请有人给我建议吗?

这是我今天早些时候提出的问题的链接,我从中获得了有关此代码的帮助Using .average with .pluck in ruby​​ on Rails app?

And*_*eko 5

这里的问题(除其他外)是你对它的误解pluck。它会返回每个用户的平均某些内容的数组。所以在你的例子中它会返回你

[30, nil]
Run Code Online (Sandbox Code Playgroud)

这就是为什么你得到90( [30, nil].first * 30=> 90)。

要获得所有用户的平均值,请使用average


解决方案:

您可以在计算平均值时使用COALESCE转换NULL为零:

User.where(industry_type: 'Heavy')
    .joins(:papers)
    .where(papers: { paper_type: ['Officepaper', nil] } )
    .average('COALESCE(papers.paper_weight, 0)') * 3
#=> 15
Run Code Online (Sandbox Code Playgroud)

需要注意的一件事是 while会在计算时COALESCE将任何null值转换为,如果没有要计算的记录,仍然会返回。0averagenilaverage

如何处理这种情况由您决定,但@max已经显示了非常简单的选项之一(假设上述查询结果写入average变量):

average.nil? ? 0 : average * 3
Run Code Online (Sandbox Code Playgroud)