Найти перекрывающиеся сезоны, где сезоны - PullRequest
1 голос
/ 05 марта 2012

У меня есть следующие настройки:

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)

Может быть, мне нужно что-то, чтобы связать пару OR для каждого date_range в экземпляре, но where() использует только AND.

Итак, короче говоря, найти перекрытие не проблема, но как мне найти перекрытие нескольких date_ranges для всей базы данных?

1 Ответ

0 голосов
/ 13 марта 2012

Самый простой способ сделать это - прямой 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.

...