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

时间:2012-11-07 21:49:48

标签: ruby-on-rails-3 activerecord sql-order-by distinct-on

我有一个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")

这很好用。

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

根据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")

哪个有效,但我也希望能够通过里程碑订购,但这不会那样。

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

更新


我想我的问题只是如何在周围的SELECTORDER BY中包装一个activerecord查询?

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

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])

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

由于

3 个答案:

答案 0 :(得分:5)

您正在尝试获取一组项目,但是您从current_user.tasks开始。

为什么不从current_user.projects开始,这保证了不同的项目?

@projects = current_user.projects.includes(:tasks).order("projects.name, tasks.milestone")

替代答案

@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}"}

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

答案 1 :(得分:1)

在用户控制器中:

inner_query = current_user.tasks.next.to_sql
@projects = Task.paginate_by_sql("select * from (#{inner_query}) as user_projects order by user_projects.#{sort_column} #{sort_direction}", :page => params[:page])

在任务模型中:

scope :next, select("distinct on (projects.id) projects.*, tasks.*").reorder("projects.id, tasks.milestone ASC")

这种方式使用postgres的强大功能只返回必要的记录,使记录集更小,更容易使用,但权衡的是RoR代码看起来不像Carlos Drew那样具有吸引力或可读性。建议。

答案 2 :(得分:0)

回答这个问题:

  

我想我的问题只是如何在周围的SELECT和ORDER B中包装一个activerecord查询

自ActiveRecord 4.0.2起,现在有php.ini

使用模型的示例:

<model>.from

您可以将其打包在inner_query = Project.joins(:tasks).select("DISTINCT ON (projects.id), *") // SELECT DISTINCT ON (projects.id) FROM projects INNER JOIN tasks ON tasks.project_id = projects.id;

from