我有一个父模型Effort has_many split_times:
class Effort
has_many :split_times
end
class SplitTime
belongs_to :effort
belongs_to :split
end
class Split
has_many :split_times
enum kind: [:start, :finish, :intermediate]
end
我需要一个范围来返回没有启动split_time的工作。这似乎应该是可能的,但到目前为止我无法做到。
我可以通过以下方式返回没有split_times的工作:
scope :without_split_times, -> { includes(:split_times).where(split_times: {:id => nil}) }
我可以返回至少有一次split_time的努力:
scope :with_split_times, -> { joins(:split_times).uniq }
这是我对我想要的范围的尝试:
scope :without_start_time, -> { joins(split_times: :split).where(split_times: {:id => nil}).where('splits.kind != ?', Split.kinds[:start]) }
但这不起作用。我需要一些能够返回没有split_time的所有努力的东西:即使努力有其他split_times,也要开始。我更喜欢Rails解决方案,但如果需要可以转到原始SQL。如果重要的话,我正在使用Postgres。
答案 0 :(得分:1)
您可以在您的条件(即splits.kind = 'start'
)上保持联接,其中包含空值(即没有匹配的行可以加入)。不同之处在于Rails'默认情况下,join
将为您提供内部联接(两个表中都有匹配的行),但您需要左联接,因为您需要检查右表中是否没有匹配的行。
使用该连接的结果,您可以按事件分组,然后计算匹配拆分的数量 - 如果它是0,那么该事件没有匹配的开始拆分!
这可能适合你:
scope :without_start_time, -> {
joins("LEFT JOIN split_times ON split_times.effort_id = efforts.id").
joins("LEFT OUTER JOIN splits ON split_times.split_id = splits.id " \
"AND splits.kind = 0").
group("efforts.id").
having("COUNT(splits.id) = 0")
}