PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

ActiveRecord:Como encontrar pais cujos TODOS os filhos correspondem a uma condição?


Usando arel pode levá-lo muito longe. A parte complicada é como você não escreve sua consulta inteira usando arel própria sintaxe de consulta?

Aqui está um truque:ao construir sua consulta usando where , se você usar arel condições, você obtém alguns métodos extras gratuitamente. Por exemplo, você pode seguir a subconsulta com .exists.not , que lhe dará um (NOT ( EXISTS (subquery))) Jogue isso no where dos pais -cláusula e você está pronto.

A questão é:como você faz referência às tabelas envolvidas? Você precisa de Arel para isso. Você poderia use o where do Arel com suas condições feias como a.eq b . Mas por que? Como é uma condição de igualdade, você pode usar as condições do Rails! Você pode fazer referência à tabela que está consultando com uma chave de hash, mas para a outra tabela (na consulta externa) você pode usar sua arel_table . Vê isto:
parents = Parent.arel_table
Parent.where(
  Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)

Você pode até reduzir o uso do Arel recorrendo um pouco a strings e contando com o fato de poder alimentar subconsultas como parâmetros para where do Rails . Não há muito uso para isso, mas não força você a se aprofundar muito nos métodos de Arel, então você pode usar esse truque ou outros operadores SQL que fazem uma subconsulta (existem outros?):
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
  Child.where(parent_id: parents[:id], other_parent_id: nil)
)

Os dois pontos principais aqui são:
  • Você pode construir subconsultas da mesma forma que está acostumado a construir consultas regulares, referenciando a tabela da consulta externa com Arel. Pode até não ser uma mesa real, pode ser um pseudônimo! Coisas loucas.
  • Você pode usar subconsultas como parâmetros para where do Rails método muito bem.