查询近9周未参加活动的跑者:ActiveRecord Scope关联查询问题
问题分析与解决建议
你的Scope逻辑存在核心问题,导致查询无结果:
- 你先用
LEFT JOIN关联attendances试图获取无参与记录的跑者,但紧接着用**内连接(INNER JOIN)**关联happenings。当attendances.id IS NULL时,attendances.happening_id也为NULL,内连接会自动过滤掉所有NULL匹配的记录,最终返回空集。
下面提供两种可行的解决方案:
方案一:使用NOT EXISTS子查询(推荐)
这种方式逻辑清晰、性能更优,直接筛选出"近9周内无任何活动参与记录"的跑者:
scope :inactive_for_nine_weeks, -> { where.not( id: Attendance.joins(:happening) .where("happenings.started_at > ?", 9.weeks.ago) .select(:runner_id) ) }
对应的SQL逻辑是:找出所有跑者,排除近9周内有活动参与记录的跑者。
方案二:修正JOIN关联逻辑
如果坚持用JOIN方式,需要把happenings也改为左连接,同时调整条件判断:
scope :inactive_for_nine_weeks, -> { left_joins(:attended_happenings) .group("runners.id") .having( "COUNT(attendances.id) = 0 OR MAX(happenings.started_at) <= ?", 9.weeks.ago ) }
这种方式通过分组聚合判断跑者的活动参与情况,逻辑相对复杂,不如子查询直观。
验证方法
可以先单独查询近9周有活动参与的跑者ID集合,确认数据是否正确:
active_runner_ids = Attendance.joins(:happening) .where("happenings.started_at > ?", 9.weeks.ago) .pluck(:runner_id) .uniq
再对比Runner.where.not(id: active_runner_ids)的结果,验证是否符合预期。
内容的提问来源于stack exchange,提问作者DavidM
相关产品推荐
相关产品推荐

