Rails范围用于没有特定子记录的父记录

问题描述 投票:2回答:1

我有一个父模型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。

sql ruby-on-rails ruby postgresql
1个回答
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")
}
© www.soinside.com 2019 - 2024. All rights reserved.