查找季节has_many date_ranges的重叠季节

时间:2012-03-05 17:10:45

标签: ruby-on-rails ruby activerecord arel

我有以下设置:

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与整个数据库的重叠?

1 个答案:

答案 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