如何将指定SQL查询转换为正确的Rails Scope?
问题分析与解决方案
你当前定义的free scope无法选中未关联SlotAlteration的Slot,核心原因是where.not(alterations: { action: 1 })的SQL逻辑问题:当Slot没有关联的SlotAlteration时,slot_alterations.action的值为NULL,而SQL中NULL != 1的运算结果是未知,这类记录会被where条件自动排除,导致符合要求的无关联Slot被过滤掉。
以下是两种符合原SQL逻辑的正确scope写法:
写法一:对应原SQL的NOT EXISTS子查询
直接复刻原SQL的NOT EXISTS逻辑,精准筛选出不存在action=1的关联SlotAlteration的Slot:
scope :free, -> { where(time_off_id: nil) .where.not( exists( SlotAlteration.select(1).where("slot_alterations.slot_id = slots.id").where(action: 1) ) ) .order(id: :asc) }
写法二:使用分组统计过滤
通过left_joins关联所有可能的SlotAlteration,按Slot分组后统计action=1的记录数,只保留统计数为0的(包含无关联的Slot):
scope :free, -> { left_joins(:alterations) .where(time_off_id: nil) .group("slots.id") .having("COUNT(CASE WHEN slot_alterations.action = 1 THEN 1 END) = 0") .order(id: :asc) }
两种写法均能满足需求:返回time_off_id为null,且不存在关联action=1的SlotAlteration的Slot(包括完全没有关联SlotAlteration的记录)。
内容的提问来源于stack exchange,提问作者RomanMin
相关产品推荐
相关产品推荐

