PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

ActiveRecord :Comment trouver des parents dont TOUS les enfants correspondent à une condition ?

Utiliser arel peut vous mener assez loin. La partie délicate est de savoir comment ne pas écrire toute votre requête en utilisant arel la propre syntaxe de requête ?

Voici une astuce :lorsque vous créez votre requête en utilisant where , si vous utilisez arel conditions, vous obtenez des méthodes supplémentaires gratuitement. Par exemple, vous pouvez suivre la sous-requête que vous avez avec .exists.not , qui vous donnera un (NOT ( EXISTS (subquery))) Mettez ça dans le where du parent -clause et vous êtes prêt.

La question est, comment référencez-vous les tables concernées ? Vous avez besoin d'Arel pour cela. Vous pourriez utiliser le where d'Arel avec ses vilaines conditions comme a.eq b . Mais pourquoi? Puisqu'il s'agit d'une condition d'égalité, vous pouvez utiliser les conditions de Rails à la place ! Vous pouvez référencer la table que vous interrogez avec une clé de hachage, mais pour l'autre table (dans la requête externe), vous pouvez utiliser son arel_table . Regarde ça :

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

Vous pouvez même réduire l'utilisation d'Arel en recourant un peu aux chaînes et en vous appuyant sur le fait que vous pouvez alimenter des sous-requêtes en tant que paramètres de where de Rails. . Cela ne sert pas à grand chose, mais cela ne vous oblige pas à trop creuser dans les méthodes d'Arel, vous pouvez donc utiliser cette astuce ou d'autres opérateurs SQL qui prennent une sous-requête (y en a-t-il même d'autres ?) :

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

Les deux points principaux ici sont :

  • Vous pouvez créer des sous-requêtes de la même manière que vous avez l'habitude de créer des requêtes régulières, en référençant la table de la requête externe avec Arel. Ce n'est peut-être même pas une vraie table, c'est peut-être un alias ! Des trucs dingues.
  • Vous pouvez utiliser des sous-requêtes comme paramètres pour where de Rails méthode très bien.