Rails5.1+PostgreSQL9.5中Arel表关系除法查询实现求助
嘿,我来帮你搞定这个Arel查询的问题!你需要的是一个能和其他作用域链式调用的查询,返回那些关联的活跃time_slots包含所有给定weekday_ids的Range记录对吧?结合Rails 5.1和PostgreSQL 9.5,咱们可以用分组+条件计数的思路来实现,用Arel写的话还能保证灵活性和可链式调用性。
核心思路
普通的where查询只能筛选出“至少有一个匹配weekday_id”的Range,但你需要的是“所有给定weekday_id都有对应的活跃time_slot”。所以我们需要:
- 关联TimeSlot表,筛选出活跃的记录
- 按Range的ID分组
- 用
having条件确保分组后,匹配的不同weekday_id数量等于给定数组的长度(这样就保证了每个给定的weekday_id都有对应的活跃time_slot)
实现作用域(支持链式调用)
直接在Range模型里定义一个作用域,用Arel来构建条件:
class Range < ApplicationRecord has_many :time_slots scope :with_all_weekday_time_slots, ->(weekday_ids) do # 如果传入空数组,直接返回空关系,避免无效查询 return none if weekday_ids.empty? # 定义Arel表对象,方便后续构建条件 range_table = self.arel_table time_slot_table = TimeSlot.arel_table joins(:time_slots) # 筛选活跃的time_slots .where(time_slot_table[:active].eq(true)) # 筛选weekday_id在给定数组内的记录 .where(time_slot_table[:weekday_id].in(weekday_ids)) # 按Range的ID分组 .group(range_table[:id]) # 关键条件:分组后不同的weekday_id数量等于输入数组的长度 .having(time_slot_table[:weekday_id].distinct.count.eq(weekday_ids.size)) end end
子查询版本(适合大数据量场景)
如果你的Range或TimeSlot表数据量很大,用子查询先筛选出符合条件的Range ID,再查询Range表可能性能更好:
class Range < ApplicationRecord has_many :time_slots scope :with_all_weekday_time_slots, ->(weekday_ids) do return none if weekday_ids.empty? range_table = self.arel_table time_slot_table = TimeSlot.arel_table # 先构建子查询:找出拥有所有指定weekday_id的活跃time_slots的range_id valid_range_ids = time_slot_table .project(time_slot_table[:range_id]) .where(time_slot_table[:active].eq(true)) .where(time_slot_table[:weekday_id].in(weekday_ids)) .group(time_slot_table[:range_id]) .having(time_slot_table[:weekday_id].distinct.count.eq(weekday_ids.size)) # 用子查询的结果筛选Range记录 where(range_table[:id].in(valid_range_ids)) end end
链式调用示例
这个作用域可以和其他Range的作用域无缝链式调用,比如你有一个active作用域:
# 假设你有一个筛选活跃Range的作用域 scope :active, -> { where(active: true) } # 链式调用:获取所有活跃且拥有指定weekday_ids的Range Range.active.with_all_weekday_time_slots([1, 2, 5, 6])
为什么用Arel?
用Arel而不是纯Rails查询语法的好处是,当你需要构建更复杂的动态条件时,Arel的API会更灵活,而且能保证生成的SQL是符合PostgreSQL语法的(比如这里的COUNT(DISTINCT weekday_id),Arel会自动正确生成)。
内容的提问来源于stack exchange,提问作者Eric Norcross
相关产品推荐
相关产品推荐

