Rails Active Record #or查询结构兼容报错及解决方法咨询
解决ActiveRecord #or查询结构不兼容问题
原代码报错原因:#or要求参与合并的两个查询必须结构完全兼容,包括关联表(joins)、选中字段(select)、排序条件(order)等。你第一个查询关联了program: :future_end_date_sessions,第二个关联了path: :future_end_date_sessions,两者的joins结构不一致,因此触发ArgumentError。
方案一:使用EXISTS子查询(推荐)
通过子查询分别判断Product关联的Program/Path是否存在符合条件的session,既避免结构不一致问题,也具备更优的查询性能:
原生SQL写法
Product.where( <<~SQL EXISTS ( SELECT 1 FROM programs JOIN sessions ON sessions.program_id = programs.id WHERE programs.id = products.learning_item_id AND products.learning_item_type = 'Program' AND sessions.future_end_date = TRUE -- 替换为future_end_date_sessions的实际筛选逻辑 ) OR EXISTS ( SELECT 1 FROM paths JOIN sessions ON sessions.path_id = paths.id WHERE paths.id = products.learning_item_id AND products.learning_item_type = 'Path' AND sessions.future_end_date = TRUE -- 替换为future_end_date_sessions的实际筛选逻辑 ) SQL )
ActiveRecord Arel写法(更贴合Rails风格)
Product.where( # 匹配关联有效Program的Product Product.arel_table[:learning_item_type].eq('Program').and( Program.where(id: Product.arel_table[:learning_item_id]) .joins(:future_end_date_sessions) .arel.exists ).or( # 匹配关联有效Path的Product Product.arel_table[:learning_item_type].eq('Path').and( Path.where(id: Product.arel_table[:learning_item_id]) .joins(:future_end_date_sessions) .arel.exists ) ) )
方案二:LEFT JOIN + WHERE筛选
通过左连接同时关联Program和Path的session,再筛选出至少一边有匹配记录的Product,最后用distinct避免重复结果:
Product.left_joins(program: :future_end_date_sessions, path: :future_end_date_sessions) .where("programs.id IS NOT NULL OR paths.id IS NOT NULL") .distinct
内容的提问来源于stack exchange,提问作者David Geismar
相关产品推荐
相关产品推荐

