PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

ActiveRecord:come trovare genitori i cui TUTTI i figli corrispondono a una condizione?

Usando arel può portarti abbastanza lontano. La parte difficile è come non scrivere l'intera query utilizzando arel sintassi della query personale?

Ecco un trucco:quando crei la tua query usando where , se usi arel condizioni, ottieni alcuni metodi extra gratuitamente. Ad esempio, puoi pedinare la sottoquery che hai lì con .exists.not , che ti darà un (NOT ( EXISTS (subquery))) Gettalo nel where del genitore -clausola e sei a posto.

La domanda è:come si fa a fare riferimento alle tabelle coinvolte? Hai bisogno di Arel per quello. Potresti usa where di Arel con le sue brutte condizioni come a.eq b . Ma perché? Poiché è una condizione di uguaglianza, puoi invece utilizzare le condizioni di Rails! Puoi fare riferimento alla tabella che stai interrogando con una chiave hash, ma per l'altra tabella (nella query esterna) puoi usare la sua arel_table . Guarda questo:

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

Puoi anche ridurre l'utilizzo di Arel ricorrendo un po' alle stringhe e basandoti sul fatto che puoi inserire sottoquery come parametri per where di Rails . Non è molto utile, ma non ti costringe a scavare troppo nei metodi di Arel, quindi puoi usare quel trucco o altri operatori SQL che accettano una sottoquery (ce ne sono anche altri?):

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

I due punti principali qui sono:

  • Puoi creare sottoquery nello stesso modo in cui sei abituato a creare query regolari, facendo riferimento alla tabella della query esterna con Arel. Potrebbe non essere nemmeno un vero tavolo, potrebbe essere uno pseudonimo! Roba da pazzi.
  • Puoi usare le sottoquery come parametri per where di Rails metodo bene.