Rails Active Record查询:筛选无指定ad_partner关联Policy的Publisher
解决方法:筛选未关联指定ad_partner的Publisher
首先,你的需求是找出完全没有包含特定ad_partner值的Policy的Publisher——不管这个Publisher有没有Policy,只要它的所有Policy里都不存在目标ad_partner,就符合条件。下面给你几种高效可行的实现方式:
方法1:用NOT EXISTS子查询(最直观高效)
这种方式逻辑最贴合你的需求,直接告诉数据库:找那些「不存在任何属于该Publisher且ad_partner为目标值的Policy」的Publisher。
target_ad_partner = "你的目标ad_partner值" publishers = Publisher.where( "NOT EXISTS (SELECT 1 FROM policies WHERE policies.publisher_id = publishers.id AND policies.ad_partner = ?)", target_ad_partner )
如果习惯链式调用的Rails风格,也可以写成:
publishers = Publisher.where.not( Policy.where("policies.publisher_id = publishers.id") .where(ad_partner: target_ad_partner) .exists? )
这种方式性能通常很好,数据库能利用索引快速排除不符合条件的记录,而且逻辑直白,不容易出错。
方法2:排除关联了目标ad_partner的Publisher
如果你的数据量不大,也可以先找出所有关联过目标ad_partner的Publisher ID,再排除它们:
target_ad_partner = "你的目标ad_partner值" # 先拿到所有关联了目标ad_partner的Publisher ID集合 publisher_ids_with_target = Policy.where(ad_partner: target_ad_partner).pluck(:publisher_id).uniq # 排除这些ID,剩下的就是符合要求的Publisher publishers = Publisher.where.not(id: publisher_ids_with_target)
这种写法代码简洁易懂,但如果Policy表数据量特别大,pluck可能会占用较多内存,这时优先选方法1。
方法3:LEFT JOIN + 分组过滤(适合复杂统计场景)
如果需要同时做一些统计(比如关联的Policy数量),可以用LEFT JOIN结合分组过滤:
target_ad_partner = "你的目标ad_partner值" publishers = Publisher.left_joins(:policies) .group("publishers.id") .having("COUNT(CASE WHEN policies.ad_partner = ? THEN 1 END) = 0", target_ad_partner)
这里的having子句会统计当前Publisher下ad_partner等于目标值的Policy数量,只有数量为0的Publisher才会被保留。
补充:按需选择指定字段
你提到当前查询里需要选择特定字段,比如publishers.name、publishers.id,可以在任何方法后面追加select:
publishers = Publisher.where( "NOT EXISTS (SELECT 1 FROM policies WHERE policies.publisher_id = publishers.id AND policies.ad_partner = ?)", target_ad_partner ).select("publishers.name, publishers.id")
内容的提问来源于stack exchange,提问作者sulleh
相关产品推荐
相关产品推荐

