Ruby on Rails - 具有加入和顺序的范围

时间:2012-07-21 00:31:00

标签: sql ruby-on-rails-3 postgresql scope

我有2个班级:

class Solution
  has_many :solution_votes

class SolutionVote
  belongs_to :solution

我的观点中有类似的内容:     


    Proposed Solution A - 2 votes up - 5 votes down
    Proposed Solution B - 1 vote up  - 0 votes down
    Proposed Solution C - 0 votes up - 0 votes down
    Proposed Solution D - 7 votes up - 2 votes down
    Proposed Solution E - 3 votes up - 1 vote down
     

我想要的是通过最多UP投票对此进行排序,以便它看起来像这样:     


    Proposed Solution D - 7 votes up - 2 votes down
    Proposed Solution E - 3 votes up - 1 vote down
    Proposed Solution A - 2 votes up - 5 votes down
    Proposed Solution B - 1 vote up  - 0 votes down
    Proposed Solution C - 0 votes up - 0 votes down
    

到目前为止,我有这个:

 scope :most_votes_up,
  select("solutions.*, count(solution_votes.id) AS votes_count").
      where(['solutions.state = ?', 'Proposed']).
      joins(:solution_votes).
      group("solutions.id").
      order("votes_count DESC")

产生这个输出:     


    Proposed Solution D - 7 votes up - 2 votes down
    Proposed Solution A - 2 votes up - 5 votes down
    Proposed Solution E - 3 votes up - 1 vote down
    Proposed Solution B - 1 vote up  - 0 votes down
    

但......我还有的问题是:
1.缺少投票的建议解决方案(显示列表中缺少上述示例中的建议解决方案C)
2.我如何仅在UP投票中指定一个计数(现在,根据哪个提议的解决方案获得MOST投票(上下),而不仅仅是向上投票?

我正在使用PostGRESQL

1 个答案:

答案 0 :(得分:3)

  1. 使用左连接(而不是默认的内连接)来包含0关联solution_votes的解决方案。

  2. 您只需在计票中仅包括投票。

  3. 以下是我修改范围的方法:

    select("solutions.*, count(solution_votes.id) AS votes_count").
      joins("left join solution_votes on solution_votes.solution_id = solutions.id").
      where(['solutions.state = ? and solution_votes.direction = ?', 'Proposed', 'up']).
      group("solutions.id").
      order("votes_count DESC")
    

    这对您的列名做了一些假设,但您应该能够将其定制为您的实际架构而不会有太多麻烦。我也把joins放在where之前 - 这在技术上不会有所作为,但这是SQL需要的顺序,这对我来说更具逻辑意义。

    编辑: 听起来好像你想把vot_count保持为所有选票的数量,但仍然按照投票数来排序。我不确定为什么会这样,除非你在返回的Solution对象上调用.votes_count,但它是可能的。为此,您可以从count聚合切换到sum,然后执行一些处理匹配您想要计数为1的条件的记录,以及那些不匹配为0的记录。他们自己,case表达式,如sum(case when solution_votes.direction = 'up' then 1 else 0 end),或做一些创意转换,将布尔值转换为整数,例如sum(cast(solution_votes.direction = 'up' as integer))。这两个都可行 - 总和将是向上投票的总数,然后您可以在订单子句中使用。选择第一个,没有特殊原因,我们最终得到以下修订范围:

    select("solutions.*, count(solution_votes.id) AS votes_count, sum(case when solution_votes.direction = 'up' then 1 else 0 end) as up_votes").
      joins("left join solution_votes on solution_votes.solution_id = solutions.id").
      where(['solutions.state = ? and solution_votes.direction = ?', 'Proposed', 'up']).
      group("solutions.id").
      order("up_votes DESC")