如何为另一个属性的任何给定值选择具有属性最大值的每个模型?

时间:2016-04-21 12:21:42

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

我的Work模型包含video_iduser_id和其他一些简单字段。我需要在页面上显示最后12个作品,但每个用户只需要1个。目前我试图这样做:

 def self.latest_works_one_per_user(video_id=nil)
   scope = self.includes(:user, :video)
   scope = video_id ? scope.where(video_id: video_id) : scope.where.not(video_id: nil)
   scope = scope.order(created_at: :desc)
   user_ids = works = []
   scope.each do |work|
     next if user_ids.include? work.user_id
     user_ids << work.user_id
     works << work
     break if works.size == 12
   end
   works
 end

但我确信有一种更优雅,更快捷的方式,特别是当作品数量增加时。

1 个答案:

答案 0 :(得分:1)

这是一个适用于任何SQL数据库且只需最小调整的解决方案。是否认为它的优雅与否取决于你对SQL的喜爱程度。

def self.latest_works_one_per_user(video_id=nil)
   scope = includes(:user, :video)
   scope = video_id ? scope.where(video_id: video_id) : scope.where.not(video_id: nil)
   scope.
     joins("join (select user_id, max(created_at) created_at
                    from works group by created at) most_recent
                  on works.user_id = most_recent.user_id and
                    works.created_at = most_recent.created_at").
     order(created_at: :desc).limit(12)
end

仅当user_id和created_at的组合是唯一的时才有效。如果该组合不是唯一的,那么您将获得超过12行。

可以在MySQL中更简单地完成。 MySQL解决方案在Postgres中不起作用,我不知道在Postgres中有更好的解决方案,虽然我确定有一个。