traer subconsultas repetir repetidos registros mostrar eliminar ejemplos duplicados consultas consulta complejas agrupar sql ruby-on-rails ruby-on-rails-3 activerecord

repetir - subconsultas sql



Encuentra todos los registros que tienen un recuento de una asociaciĆ³n mayor que cero (6)

1) Para obtener Proyectos con al menos 1 vacante:

Project.joins(:vacancies).group(''projects.id'')

2) Para obtener Proyectos con más de 1 vacante:

Project.joins(:vacancies).group(''projects.id'').having(''count(project_id) > 1'')

3) O, si el modelo de Vacancy establece el contador de caché:

belongs_to :project, counter_cache: true

entonces esto también funcionará:

Project.where(''vacancies_count > ?'', 1)

La regla de inflexión para vacancy puede necesitar ser especificada manualmente ?

Intento hacer algo que pensé que sería simple, pero parece que no lo es.

Tengo un modelo de proyecto que tiene muchas vacantes.

class Project < ActiveRecord::Base has_many :vacancies, :dependent => :destroy end

Quiero obtener todos los proyectos que tienen al menos 1 vacante. Intenté algo como esto:

Project.joins(:vacancies).where(''count(vacancies) > 0'')

pero dice

SQLite3::SQLException: no such column: vacancies: SELECT "projects".* FROM "projects" INNER JOIN "vacancies" ON "vacancies"."project_id" = "projects"."id" WHERE ("projects"."deleted_at" IS NULL) AND (count(vacancies) > 0) .


El error es decirle que las vacantes no son una columna en los proyectos, básicamente.

Esto debería funcionar

Project.joins(:vacancies).where(''COUNT(vacancies.project_id) > 0'')


Sí, las vacancies no son un campo en la unión. Creo que quieres:

Project.joins(:vacancies).group("projects.id").having("count(vacancies.id)>0")


Sin mucha magia de Rails, puedes hacer:

Project.where(''(SELECT COUNT(*) FROM vacancies WHERE vacancies.project_id = projects.id) > 0'')

Este tipo de condiciones funcionará en todas las versiones de Rails ya que gran parte del trabajo se realiza directamente en el lado de la base de datos. Además, el método de encadenamiento .count también funcionará muy bien. Me he quemado por consultas como Project.joins(:vacancies) antes. Por supuesto, hay pros y contras ya que no es DB agnóstico.


join utiliza una unión interna por defecto, por lo que usar Project.joins(:vacancies) en efecto solo devolverá proyectos que tengan una vacante asociada.

ACTUALIZAR:

Como señala @mackskatz en el comentario, sin una cláusula de group , el código anterior devolverá proyectos duplicados para proyectos con más de una vacante. Para eliminar los duplicados, use

Project.joins(:vacancies).group(''projects.id'')


# None Project.joins(:vacancies).group(''projects.id'').having(''count(vacancies) = 0'') # Any Project.joins(:vacancies).group(''projects.id'').having(''count(vacancies) > 0'') # One Project.joins(:vacancies).group(''projects.id'').having(''count(vacancies) = 1'') # More than 1 Project.joins(:vacancies).group(''projects.id'').having(''count(vacancies) > 1'')