ruby-on-rails-3 activerecord sql-order-by distinct-on

ruby on rails 3 - Aplicando un orden diferente a postgres “DISTINCT ON” utilizando rieles



ruby-on-rails-3 activerecord (3)

En el controlador de usuario:

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

Y en el modelo de tarea:

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

De esta manera, se utiliza el poder de postgres para devolver solo los registros necesarios, lo que hace que el conjunto de registros sea más pequeño y más fácil de trabajar, pero la compensación es que el código RoR no parece tan atractivo o legible como lo hace la sugerencia de Carlos Drew.

Tengo una aplicación de rieles:

user has_many :projects

user has_many :tasks, :through => :projects

project has_many :tasks

Cada tarea tiene una fecha de hito.

Para mostrar una tabla de detalles del proyecto con la fecha del próximo hito que estoy usando:

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

Esto funciona bien.

Ahora quiero poder ordenar las columnas de la tabla.

De acuerdo con Postgres, DISTINCT ON no se puede clasificar, tiene que ajustarlo en otra declaración de selección, es decir, SELECT * FROM (SELECT DISTINCT ON....) ORDER BY column_3

Pensé que la columna que estaba siendo ordenada podría ser trabajada en el SQL según sea necesario, es decir (para ordenar por nombre de proyecto DESC):

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

que funciona pero también quiero poder ordenar por hito y eso no funciona de esa manera.

¿Alguien puede decirme cómo convertir mi consulta de rieles para que pueda ser ordenada por cualquiera de las columnas?

ACTUALIZAR

Supongo que mi pregunta es, simplemente, ¿cómo encierro una consulta de registro de registro en un entorno SELECT y ORDER BY ?

Creo que lo he conseguido utilizando:

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

¿Es esa la mejor manera o alguien puede pensar en una mejor manera? - find / paginate_by_sql parece una solución alternativa y hubiera preferido permanecer dentro de los reinos de la consulta de registro de archivos.

Gracias


Estás tratando de obtener un conjunto de proyectos pero estás empezando con current_user.tasks .

¿Por qué no empezar con current_user.projects , que garantiza proyectos distintos?

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

Respuesta alternativa

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

Eso le dará una fila para cada proyecto, con un valor mínimo de tareas.milestone calculado, accesible en el resultado de la fila del proyecto a través de next_milestone. No hay registro de tareas adicionales, solo la próxima fecha de hito.


Para responder a esta pregunta:

Supongo que mi pregunta es simplemente cómo encierro una consulta de registro de registro en un entorno SELECT y ORDEN B

Desde ActiveRecord 4.0.2 ahora hay <model>.from .

Un ejemplo utilizando tus modelos:

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;

Puedes envolverlo en un from :

sorted_query = Project.from(inner_query, :projects).order(:name)