这与我在这里尝试做的类似。
我会尝试使用子查询,将 Period 加入自身,如下所示:
class Period < ActiveRecord::Base
attr_accessible :end_at, :season_id, :start_at
belongs_to :season
scope :in_seasons, ->(season_ids) { joins{season}.where{id.in(season_ids)} }
def self.find_gaps(start_date, end_date)
season_ids = ["1", "2", "3"]
scope = select{[end_at.as(`gap_start`), `min(self_join.start_at)`.as(`gap_end`)]}
scope = scope.joins{"LEFT JOIN (" + Period.in_seasons(season_ids).to_sql + ") AS self_join ON self_join.end_at <= periods.start_at"}
scope = scope.where{(`self_join.start_at` != nil) & (`gap_start` < start_date) & (`gap_end` > end_date)}
scope = scope.group{`gap_end`}.having{end_at < `min(self_join.start_at)`}
end
end
在 Rails 控制台中,Period.find_gaps('2001-01-01', '2010-01-01').to_sql
产生(格式是我自己的):
SELECT
\"periods\".\"end_at\" AS gap_start,
min(self_join.start_at) AS gap_end
FROM \"periods\"
LEFT JOIN
(SELECT \"periods\".*
FROM \"periods\"
INNER JOIN \"seasons\" ON \"seasons\".\"id\" = \"periods\".\"season_id\"
WHERE \"periods\".\"id\" IN (1, 2, 3)
) AS self_join ON self_join.end_at <= periods.start_at
WHERE ((self_join.start_at IS NOT NULL AND gap_start < '2001-01-01' AND gap_end > '2010-01-01'))
GROUP BY gap_end
HAVING \"periods\".\"end_at\" < min(self_join.start_at)
看起来你想要达到的效果......至少是内部部分。
希望能帮助到你。