如何从ActiveRecord中获取每组的最新记录?

时间:2014-01-22 17:04:57

标签: ruby-on-rails ruby activerecord

在我的Ruby on Rails应用程序中,我有一个像这样的数据库结构:

Project.create(:group => "1", :date => "2014-01-01")
Project.create(:group => "1", :date => "2014-01-02")
Project.create(:group => "1", :date => "2014-01-03")

Project.create(:group => "2", :date => "2014-01-01")
Project.create(:group => "2", :date => "2014-01-02")
Project.create(:group => "2", :date => "2014-01-03")

# and so forth...

如何使用ActiveRecord获取每个group的最新记录?

解决方案可能很简单,但我无法理解这一点。

感谢您的帮助。

6 个答案:

答案 0 :(得分:44)

的Postgres

在Postgres中,可以通过以下查询来实现。

SELECT DISTINCT ON ("group") * FROM projects
ORDER BY "group", date DESC, id DESC

由于此处的date列可能不是唯一的,因此我在ORDER BY上添加了一个额外的id DESC条款来打破有利于具有更高ID的记录的关系,以防两个组中的记录具有相同的日期。您可能希望使用其他列,例如上次更新的日期/时间,这取决于您的用例。

继续,不幸的是ActiveRecord没有DISTINCT ON的API,但我们仍然可以使用select的纯SQL:

Project.select('DISTINCT ON ("group") *').order(:group, date: :desc, id: :desc)

或者如果您更喜欢使用ARel而不是使用原始SQL:

p = Project.arel_table
Project.find_by_sql(
  p.project(p[Arel.star])
   .distinct_on(p[:group])
   .order(p[:group], p[:date].desc, p[:id].desc)
)

的MySQL

对于像MySQL这样的其他数据库,遗憾的是这并不方便。有多种解决方案可供选择,例如参见this answer

答案 1 :(得分:3)

这对我有用

ids = Message.select("MAX(id) AS id").group(:column_name).collect(&:id)
@result = Message.order("created_at DESC").where(:id => ids)

答案 2 :(得分:3)

我花了一些时间对此作斗争,并认为我会分享我发现的最干净,非常简单的解决方案(假设date或其他排序字段包含唯一值):

Project.group(:group).maximum(:date)

qarol上发布this comment的提示。

答案 3 :(得分:0)

以下基于 this link 的解决方案适用于 MySQL,并且可以扩展到 group 表中的所有字段。

Project.select(:group, 'MAX(date) AS date').group(:group)

答案 4 :(得分:-6)

这样的东西?

Project.select(:group).map(&:group).uniq.each do |grp|
  puts Project.where(group: grp).order("date DESC").last
end

这将遍历所有群组并识别唯一群组。在您的示例中,它应返回[“1”,“2”]。然后它遍历该数组并选择组ID为1的最后一个Project和组ID为2的最后一个Project。

**更新**

刚刚意识到你说“最新”而不是“最后”需要添加订单以确保最新作品。最后仍然只拉一个。

答案 5 :(得分:-10)

Project.where(:group => "1", :date => "2014-01-01").last

.last就是你要找的。