代码之家  ›  专栏  ›  技术社区  ›  sulleh

Rails活动记录查询:在子条件上联接以仅包括匹配结果

  •  0
  • sulleh  · 技术社区  · 6 年前

    我有两种型号- 出版商 政策 。策略属于发布者,发布者有许多策略。在策略模型中,有一列名为“ ad\U合作伙伴 “,我希望找到在ad合作伙伴中没有包含特定价值的策略的发布者。最终目标是列出没有与特定ad\U合作伙伴关联的任何策略的发布者。

    这是我当前的查询:

    test = Publisher.joins(:policies).select('publishers.name, 
    publishers.id, publishers.domain').where.not("policies.ad_partner ILIKE 
    ?", 'indexexchange.com').group("publishers.id, 
    publishers.name").limit(10)
    

    输出如下所示:

     +----+------------------+---------------------+
    | id | name             | domain              |
     +----+------------------+---------------------+
    | 1  | Business Insider | businessinsider.com |
    | 2  | Wired            | wired.com           |
    | 3  | CNET             | cnet.com            |
    | 4  | Weather Channel  | weather.com         |
    | 5  | Time Inc         | time.com            |
    | 6  | IGN              | ign.com             |
    | 7  | CBS              | cbs.com             |
    | 8  | NBC              | nbc.com             |
    | 9  | TMZ              | tmz.com             |
    | 10 | HGTV             | hgtv.com            |
    +----+------------------+---------------------+
    

    这是不正确的,因为我知道大多数(如果不是所有的话)出版商都有包含 indexexchange。com公司 作为ad\U合作伙伴中的一个价值。我怀疑的是,查询的意思是“好的,我们正在从加入列表中删除策略,并输出按发布者分组的剩余策略,而实际上我想找到具有此条件的发布者,而不是像它看起来那样创建条件。我感觉这里有一个明显的错误,但我一直在努力找到它。有什么想法吗?

    1 回复  |  直到 6 年前
        1
  •  2
  •   mu is too short    6 年前

    您正在寻找:

    没有与特定ad\U合作伙伴关联的任何策略的发布者

    所以说得没错。首先找到 有这样的政策:

    Policy.where('ad_partner ilike ?', partner).select(:publisher_id)
    

    然后查找不在该列表中的出版商:

    Publisher.where.not(
      id: Policy.select(:publisher_id).where('ad_partner ilike ?', partner)
    )
    

    包括 select(:publisher_id) Policy 查询将告诉ActiveRecord使用子查询,因此结果将是如下所示的SQL:

    select *
    from publisher
    where id not in (
      select publisher_id
      from policies
      where ad_partner ilike 'indexexchange.com'
    )
    

    这会让你找到你想要的出版商,而不会有副本。然后,您可以添加所需的任何顺序和限制。

    原始查询无法按您希望的方式工作,因为联接将生成包含所有内容的行:

    publisher1_columns, policy_with_partner
    publisher1_columns, policy_without_partner
    publisher1_columns, policy_without_partner
    publisher2_columns, policy_without_partner
    ...
    

    然后您的WHERE将只排除联接中的第一行,留下您不想要的两个“publisher1”行。


    ilike 'indexexchange.com' 只是一种复杂的不区分大小写的相等方式。如果你想进行模式匹配,你会说:

    where('ad_partner ilike ?', "%#{partner}%")
    

    相反