【问题标题】:Trying to select all objects where at least one associated object doesn't match the query尝试选择至少一个关联对象与查询不匹配的所有对象
【发布时间】:2019-05-24 16:36:53
【问题描述】:

我有两个相关的模型。一个Product 有很多DescriptorFiles,一个DescriptorFile 有一个布尔属性approved

我想查找所有关联描述符文件均未获批准的产品。

也就是说:我要查找ALL descriptor_files为approved: false的所有产品。

我刚刚提出了一个解决方案,但我更愿意通过活动记录查询来完成这一切:

Product.all - Product.joins(:descriptor_files).where(descriptor_files: {approved: true})

这可行,但如前所述,如果我能返回一个活动记录对象,那就太好了。

谢谢!

【问题讨论】:

    标签: ruby-on-rails join activerecord


    【解决方案1】:

    在 Rails 5+ 中,您可以使用 where.not 所以在这种情况下,您的查询将是

    Product.where.not(id: 
      Product.select(:id).joins(:descriptor_files)
          .where(descriptor_files: {approved: true})
    ) 
    

    这将使用原始版本的子查询作为NOT IN 子句。 生成的 SQL

    SELECT 
      products.* 
    FROM 
      products
    WHERE 
      products.id NOT IN ( 
        SELECT 
          products.id
        FROM 
          products
          INNER JOIN descriptors ON descriptors.product_id = products.id
        WHERE 
          descriptors.approved = true
      )
    

    【讨论】:

    • 我知道where.not,但我从未考虑过传递我想要排除的 id 数组。这是非常好的。非常感谢。
    【解决方案2】:

    您可以 LEFT JOIN 已批准的描述符文件,并确保您只检索 未加入任何内容的记录。 (这也将查询根本没有描述符文件的产品)。

    Product.joins('LEFT OUTER JOIN descriptor_files ON descriptor_files.product_id = product.id AND descriptor_files.approved = true')
           .where(descriptor_files: { id: nil })
    

    不幸的是,连接必须手动编写,尽管您可以使用 Arel 来生成 Join 子句。

    【讨论】:

    • 希望我对 SQL 有足够的了解以了解其工作原理。谢谢。
    【解决方案3】:

    或者,您可以将left_outer_joins 用于rails 5 +

    results = Product.left_outer_joins(:descriptor_files)
                          .where(descriptor_files: {approved: false})
    

    【讨论】:

    • 这将查找任何描述符文件为假的产品,而不是它们全部为假的产品。连接表上带有 where 条件的左连接也是内连接
    猜你喜欢
    • 2022-06-25
    • 1970-01-01
    • 2014-04-06
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2023-03-17
    相关资源
    最近更新 更多