根据条件加入并选择计数

时间:2016-05-02 06:12:37

标签: ruby-on-rails ruby activerecord

我正在努力获得购买量最多的前5部电影。所以我提出了这个问题:

@movies = Movie.joins(:purchases)
          .select('movies.id, movies.name, count(purchases.id) as purchases_count')
          .group('movies.id').order('purchases_count desc').limit(5)

然后我在我的视图中显示前5部电影以及他们的购买类型数量(购买有2种类型,"部分"或"完整")。

<% @movies.each do |t| %>
<%= t.name %>
Partial purchase:
<%= t.purchases.where(type: "partial").count %>
Full purchase:
<%= t.purchases.where(type: "full").count %>
<% end %>

这是有效的,但是,由于电影中的选择计数,我担心这会导致N + 1个查询。我能想到的一些解决方案包括:

1)有没有办法按select方法过滤购买次数?例如:

@movies = Movie.joins(:purchases)
          .select('movies.id, movies.name, count(purchase.where(type: "partial")) as purchases_partial_count, count(purchases.id) as purchases_count')

2)我可以从@movies中提取ID并编写另一个查询,例如:  @purchases = Movie.find_by(@movies_ids).includes(:purchases)并使用length替换我的观看中的count

我愿意接受其他更好的解决方案,谢谢,任何帮助都将受到赞赏!

2 个答案:

答案 0 :(得分:4)

你可以通过编写更多的自定义SQL来实现它,就像你建议的替代1并使用SUM CASE SQL sum with condition

@movies = Movie.joins(:purchases)
      .select('movies.id, movies.name, count(purchases.id) as purchases_count, 
      SUM(CASE WHEN purchases.type = "partial" THEN 1 ELSE 0) as partial_count,
      SUM(CASE WHEN purchases.type = "full" THEN 1 ELSE 0) as full_count')
      .group('movies.id').order('purchases_count desc').limit(5)

答案 1 :(得分:0)

应该是

@movies = Movie.joins(:purchase)。选择(&#39; movies.id,movies.name,count(purchases.id)作为purchases_count,SUM(CASE WHEN purchases.type =&#34; partial& #34;那么1 ELSE 0 END)作为partial_count,SUM(例如,购买时,类型为&#34;完整&#34;那么1,结束0结束)为full_count&#39;)。group(&#39; movies.id& #39;)。订单(&#39; purchases_count desc&#39;)。limit(5)