我有以下设置:
class Season < AR::Base
has_many :date_ranges
end
class DateRange < AR::Base
# has a :starts_at & :ends_at
end
如何从季节实例中找到所有重叠的季节?我已经尝试了几个不同的查询(下面)。但是我一直在遇到的问题是,即时检查的季节也有多个date_ranges。我可以用循环解决它,但我宁愿只使用查询。
此查询查找重叠的所有季节,但它仅对1个输入date_range执行此操作
Season.joins(:date_ranges).where("starts_at <= ? AND ends_at >= ?", ends_at, starts_at
)
也许我需要为实例上的每个date_range将一些OR链接在一起,但where()
仅使用AND。
简而言之,找到重叠不是问题,但如何找到多个date_ranges与整个数据库的重叠?
答案 0 :(得分:0)
最简单的方法是通过直接SQL。像这样:
DateRange.find_by_sql(%q{
select a.*
from date_ranges a
join date_ranges b on
a.id < b.id
and (
(a.ends_at >= b.starts_at and a.ends_at <= b.ends_at)
or (a.starts_at >= b.starts_at and a.starts_at <= b.ends_at)
or (a.starts_at <= b.starts_at and a.ends_at >= b.ends_at)
)
where season_id = ?
}, season_id)
基本思想是将表格连接到自身,以便您可以轻松地比较范围。 a.id < b.id
可以获得独特的结果,并过滤掉“范围匹配”的情况。内部or
条件检查两种类型的重叠:
[as-----ae] [as-----ae]
[bs-----be] [bs-----be]
和
[as--------------ae] [as----ae]
[bs----be] [bs--------------be]
您可能想要考虑端点,如果查询只在端点处匹配并且可能不是您想要的那个,那么该查询会认为两个间隔重叠。
据推测,您已经对(season_id, starts_at, ends_at)
三元组有一个独特的约束,并且可能您已经确保starts_at <= ends_at
。