【问题标题】:Rails Active Record Query: Join on Child Condition to include only matching resultsRails Active Record Query:加入子条件以仅包含匹配的结果
【发布时间】:2018-03-24 19:46:43
【问题描述】:

我有两个模型 - Publisher 和 Policy。策略属于发布者,发布者有许多策略。在政策模型中,有一个名为“ad_partner”的列,我希望找到在广告合作伙伴中没有包含特定值的政策的发布商。最终目标是列出没有与特定 ad_partner 关联的任何政策的发布商。

这是我当前的查询:

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_partner 中的值的政策。我怀疑正在发生的事情是查询说“好的,我们正在从 JOIN 列表中删除策略,并输出按发布者分组的剩余策略,而实际上我想查找具有此条件的发布者,而不是创建条件为它似乎在做。我感觉这里有一个明显的错误,但我一直在努力寻找它。有什么想法吗?

【问题讨论】:

  • 你有模特吗?请张贴。也请您的 schema.rb

标签: sql ruby-on-rails postgresql activerecord rails-activerecord


【解决方案1】:

您正在寻找:

没有与特定广告合作伙伴相关的任何政策的发布商

那就这么说吧。首先找到确实有这样政策的出版商:

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

然后找到不在该列表中的发布者:

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

在Policy 查询中包含select(:publisher_id) 将告诉ActiveRecord 使用子查询,因此结果将是这样的SQL:

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

这将为您提供您所追求的出版商而不会重复。然后你可以添加任何你需要的顺序和限制。

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

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

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


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

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

改为。

【讨论】:

  • 感谢您的回复和澄清 - 你说得对,我没有在查询中问“正确的问题”。这可行:Publisher.where.not( id: Policy.select(:publisher_id).where('ad_partner ilike ?', partner) ) 但是它包括可能没有任何政策的发布商,这不太有用。如果我想运行相同的查询,但只希望列表包含拥有政策的发布商,而不是特定的 ad_partner,该怎么办?
  • 我想我已经回答了我自己的问题 - 我将它分成两个查询 active = Publisher.joins(:policies).group('publishers.id') 以选择活跃的发布者,然后运行您的查询:missing2 = active.select(:id, :name, :domain, :articles_count).where.not( id: Policy.select(:publisher_id).where('ad_partner ilike ?', 'indexexchange.com')).order(:id)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
  • 2012-02-28
  • 2012-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多