Estoy tratando de 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 conseguir todos los proyectos que tengan 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).

Project.joins(:vacancies).distinct?1) Para conseguir proyectos con al menos 1 vacante:
2) Para obtener proyectos con más de 1 vacante:
3) O, si el
Vacancymodelo establece la caché del contador:entonces esto también funcionará:
¿Es
vacancyposible que sea necesario especificar manualmente la regla de inflexión para ?fuente
Project.joins(:vacancies).group('projects.id').having('count(vacancies.id) > 1')? Consultando el número de vacantes en lugar de losprojects.id,project_idyvacancies.id. Elegí contarproject_idporque es el campo en el que se realiza la unión; la columna vertebral de la unión si se quiere. También me recuerda que esta es una tabla de combinación.Sí,
vacanciesno es un campo en la combinación. Creo que quieres:fuente
fuente
Realizar una unión interna a la tabla has_many combinada con un
groupouniqes potencialmente muy ineficiente, y en SQL esto se implementaría mejor como una semi-unión que se usaEXISTScon una subconsulta correlacionada.Esto permite al optimizador de consultas sondear la tabla de vacantes para verificar la existencia de una fila con el project_id correcto. No importa si hay una fila o un millón que tienen ese project_id.
Eso no es tan sencillo en Rails, pero se puede lograr con:
Del mismo modo, busque todos los proyectos que no tengan vacantes:
Editar: en las versiones recientes de Rails, recibe una advertencia de desaprobación que le indica que no dependa de
existsser delegado a arel. Arregle esto con:Editar: si no se siente cómodo con SQL sin formato, intente:
Puede hacer que esto sea menos complicado agregando métodos de clase para ocultar el uso de
arel_table, por ejemplo:... entonces ...
fuente
Vacancy.where("vacancies.project_id = projects.id").exists?producetrueofalse.Project.where(true)es unArgumentError.Vacancy.where("vacancies.project_id = projects.id").exists?no se ejecutará; generará un error porque laprojectsrelación no existirá en la consulta (y tampoco hay un signo de interrogación en el código de muestra anterior). Entonces, descomponer esto en dos expresiones no es válido y no funciona. Recientemente, RailsProject.where(Vacancies.where("vacancies.project_id = projects.id").exists)plantea una advertencia de desaprobación ... Actualizaré la pregunta.En Rails 4+, también puedes usar includes o eager_load para obtener la misma respuesta:
fuente
Creo que hay una solución más sencilla:
fuente
Sin mucha magia de Rails, puedes hacer:
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
.countmétodo de encadenamiento también funcionará bien. Me han quemado consultas comoProject.joins(:vacancies)antes. Por supuesto, existen pros y contras, ya que no es independiente de DB.fuente
También puede usar
EXISTScon enSELECT 1lugar de seleccionar todas las columnas de lavacanciestabla:fuente
El error es decirte que las vacantes no es una columna en los proyectos, básicamente.
Esto debería funcionar
fuente
aggregate functions are not allowed in WHERE