Rails has_many through关联下两个scope联合查询count值大于单个scope的问题
问题原因
核心问题是joins关联查询产生的重复行导致计数逻辑和预期不符:
joins(:bookings)默认使用内连接,当1个Customer关联了多个满足bookings.time < DateTime.now条件的booking时,SQL结果会为每个匹配的booking返回1行重复的Customer数据,Rails默认的count统计的是返回结果的总行数,不是去重后的Customer数量。
三个计数结果的逻辑说明
Customer.who_booked_trips.count:无关联查询,直接统计customers表中won_deal = true的行数,结果是准确的653个不同Customer。Customer.already_finished.count:统计的是「Customer+符合时间条件的booking」的关联行总数,662是包含重复Customer的行计数,真实符合条件的不同Customer数量必然小于等于662。Customer.who_booked_trips.already_finished.count:统计的是同时满足won_deal = true、且有关联符合时间条件booking的所有关联行总数,只要这些Customer关联的符合条件booking数量足够多,总行数完全可以超过653。
修复方案
如果需要统计去重后的Customer数量,有两种常用方案:
- 计数时加去重逻辑
# 统计去重后的Customer数量 Customer.who_booked_trips.already_finished.distinct.count
- 改造scope避免产生重复行
用exists子查询替换joins,从根源上避免生成重复的Customer行:
scope :already_finished, -> { where( Booking.joins(:hangout) .where("hangouts.customer_id = customers.id") .where("bookings.time < ?", DateTime.now) .arel.exists ) }
改造后直接调用count就会返回正确的去重Customer数量,无需额外加distinct。
内容的提问来源于stack exchange,提问作者wachichornia
相关产品推荐
相关产品推荐

