使用rails将不同的顺序应用于postgres"DISTINCT ON"

use*_*573 17 activerecord sql-order-by distinct-on ruby-on-rails-3

我有一个rails应用程序:

user has_many :projects

user has_many :tasks, :through => :projects

project has_many :tasks

每项任务都有一个里程碑日期.

要显示我正在使用的下一个里程碑日期的项目详细信息表:

@projects = current_user.tasks.joins(:project).select("distinct on (projects.id) projects.*, tasks.*").reorder("projects.id, tasks.milestone ASC")
Run Code Online (Sandbox Code Playgroud)

这很好用.

我现在希望能够对表列进行排序.

根据Postgres DISTINCT ON不可排序,你必须将它包装在另一个select语句中,即SELECT * FROM (SELECT DISTINCT ON....) ORDER BY column_3

我确实认为订购的列可以根据需要在SQL中使用,即(按项目名称DESC排序):

@projects = current_user.tasks.joins(:project).select("distinct on (projects.name) projects.*, tasks.*").reorder("projects.name DESC, tasks.milestone ASC")
Run Code Online (Sandbox Code Playgroud)

哪个有效,但我也希望能够通过里程碑进行排序,但这样做不起作用.

有人能告诉我如何转换我的rails查询,以便可以通过任何列进行排序吗?

UPDATE


我想我的问题很简单我怎么在周围包裹一个ActiveRecord的查询SELECT和ORDER BY?

我想我已经成功实现了它:

inner_query = current_user.tasks.select("distinct on (projects.id) projects.*, tasks.*").reorder("projects.id, tasks.milestone ASC").to_sql
@projects = Task.paginate_by_sql("select * from (#{inner_query}) as user_projects order by user_projects.name", :page => params[:page])
Run Code Online (Sandbox Code Playgroud)

这是最好的方式还是有人能想到更好的方式? - find/paginate_by_sql似乎是一种解决方法,我宁愿保持在activerecord查询的范围内.

谢谢

Car*_*rew 5

你正试图获得一组项目,但是你开始了current_user.tasks.

为什么不从一开始就current_user.projects保证不同的项目?

@projects = current_user.projects.includes(:tasks).order("projects.name, tasks.milestone")
Run Code Online (Sandbox Code Playgroud)

替代答案

@projects = current_user.projects.joins(:tasks).select('projects.*, min(tasks.milestone) as next_milestone').order('projects.name').group('projects.id')
@projects.each{|p| puts "#{p.name} #{p.next_milestone}"}
Run Code Online (Sandbox Code Playgroud)

这将为每个项目提供一行,计算出最小tasks.milestone值,可通过next_milestone在项目行结果中访问.没有额外的任务记录,只是下一个里程碑日期.