sql >> Base de Datos >  >> RDS >> PostgreSQL

ActiveRecord:¿Cómo encontrar padres cuyos TODOS los niños coincidan con una condición?

Usando arel puede llevarte bastante lejos. La parte complicada es cómo no escribes tu consulta completa usando arel ¿La sintaxis de consulta propia?

Aquí hay un truco:al construir su consulta usando where , si usa arel condiciones, obtienes algunos métodos adicionales gratis. Por ejemplo, puede seguir la subconsulta que tiene allí con .exists.not , que le dará un (NOT ( EXISTS (subquery))) Tira eso en el where de los padres -cláusula y listo.

La pregunta es, ¿cómo hace referencia a las tablas involucradas? Necesitas a Arel para eso. podrías usa el where de Arel con sus feas condiciones como a.eq b . ¿Pero por qué? Como es una condición de igualdad, ¡puedes usar las condiciones de Rails en su lugar! Puede hacer referencia a la tabla que está consultando con una clave hash, pero para la otra tabla (en la consulta externa) puede usar su arel_table . Mira esto:

parents = Parent.arel_table
Parent.where(
  Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)

Incluso puede reducir el uso de Arel recurriendo un poco a cadenas y confiando en el hecho de que puede alimentar subconsultas como parámetros al where de Rails . No sirve de mucho, pero no te obliga a profundizar demasiado en los métodos de Arel, por lo que puedes usar ese truco u otros operadores SQL que toman una subconsulta (¿hay incluso otros?):

parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
  Child.where(parent_id: parents[:id], other_parent_id: nil)
)

Los dos puntos principales aquí son:

  • Puede crear subconsultas de la misma forma en que está acostumbrado a crear consultas regulares, haciendo referencia a la tabla de consultas externas con Arel. Puede que ni siquiera sea una tabla real, ¡puede que sea un alias! Cosas locas.
  • Puede usar subconsultas como parámetros para el where de Rails método muy bien.