In my Ruby on Rails application I have a database structure like this:
Project.create(:group => \"1\", :date => \"2014-01-01\")
Project.create(:group =
In Postgres, this can be achieved with the following query.
SELECT DISTINCT ON ("group") * FROM projects
ORDER BY "group", date DESC, id DESC
Because the date
column might not be unique here, I have added an additional ORDER BY
clause on id DESC
to break ties in favor of the record with the higher ID, in case two records in a group have the same date. You might instead want to use another column like the date/time of the last update or so, that depends on your use case.
Moving on, ActiveRecord unfortunately has no API for DISTINCT ON
, but we can still use plain SQL with select
:
Project.select('DISTINCT ON ("group") *').order(:group, date: :desc, id: :desc)
or if you prefer using ARel instead of having raw 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)
)
For other databases like MySQL this is unfortunately not as convenient. There are a variety of solutions available, see for example this answer.
This works for me
ids = Message.select("MAX(id) AS id").group(:column_name).collect(&:id)
@result = Message.order("created_at DESC").where(:id => ids)
I spent some time battling this and thought I'd share what I found to be the cleanest and stunningly easy solution (assuming date
or other sorting field contains unique values):
Project.group(:group).maximum(:date)
Hat tip to qarol for posting this in this comment.
Project.where(:group => "1", :date => "2014-01-01").last
.last is what you are looking for.
Something like this?
Project.select(:group).map(&:group).uniq.each do |grp|
puts Project.where(group: grp).order("date DESC").last
end
This will go through all your groups and identify the unique ones. In your example it should return ["1", "2"]. Then it iterates over that array and selects the last Project with a group id of 1 and the last Project with a group id of 2.
** Update **
Just realized you said "latest" and not "last" which required adding an order to ensure latest works. Last still pulls just one.