【问题标题】:How to combine overlapping date ranges in MySQL?如何在 MySQL 中组合重叠的日期范围?
【发布时间】:2016-07-11 18:34:45
【问题描述】:

我有一张桌子“lessons_holidays”。它可以包含多个假期日期范围,即

"holiday_begin"    "holiday_end" 
2016-06-15         2016-06-15
2016-06-12         2016-06-16
2016-06-15         2016-06-19
2016-06-29         2016-06-29

如果日期范围重叠,我想合并每个条目。我需要这样的输出:

"holiday_begin"    "holiday_end" 
2016-06-12         2016-06-19
2016-06-29         2016-06-29

SQL:以下 sql 语句加载所有行。现在我被卡住了。

SELECT lh1.holiday_begin, lh1.holiday_end 
FROM local_lessons_holidays lh1 
WHERE lh1.holiday_impact = '1' AND
(DATE_FORMAT(lh1.holiday_begin, '%Y-%m') <= '2016-06' AND DATE_FORMAT(lh1.holiday_end, '%Y-%m') >= '2016-06') AND
lh1.uid = '1' 

【问题讨论】:

  • 这在 MySQL 中很难做到。您还有其他可以使用的数据库吗?

标签: mysql date-range


【解决方案1】:

这是一个难题,因为您使用的是 MySQL,所以变得更加困难。这是一个想法。查找每个组中所有假期的开始日期。然后“开始”的标志的累积总和处理这些组。剩下的只是聚合。

假设您没有重复记录,以下应该可以满足您的要求:

select min(holiday_begin) as holiday_begin, max(holiday_end) as holiday_end
from (select lh.*, (@grp := @grp + group_flag) as grp
      from (select lh.*,
                   (case when not exists (select 1
                                          from lessons_holidays lh2
                                          where lh2.holiday_begin <= lh.holiday_end and
                                                lh2.holiday_end > lh.holiday_begin and
                                                (lh2.holiday_begin <> lh.holiday_begin or
                                                 lh2.holiday_end < lh.holiday_end)

                                         )
                         then 1 else 0
                    end) as group_flag
            from lessons_holidays lh
           ) lh cross join
           (select @grp := 0) params
      order by holiday_begin, holiday_end
    ) lh
group by grp;

如果您有重复,只需在表的最内层引用上使用select distinct

Here 是一个 SQL Fiddle。

编辑:

这个版本似乎更好用:

select min(holiday_begin) as holiday_begin, max(holiday_end) as holiday_end
from (select lh.*, (@grp := @grp + group_flag) as grp
      from (select lh.*,
                   (case when not exists (select 1
                                          from lessons_holidays lh2
                                          where lh2.holiday_begin <= lh.holiday_begin and
                                                lh2.holiday_end > lh.holiday_begin and
                                                lh2.holiday_begin <> lh.holiday_begin and
                                                lh2.holiday_end <> lh.holiday_end
                                         )
                         then 1 else 0
                    end) as group_flag
            from lessons_holidays lh
           ) lh cross join
           (select @grp := 0) params
      order by holiday_begin, holiday_end
    ) lh
group by grp;

如图here

【讨论】:

  • 非常感谢。我稍后会试试看。
  • 结果我只得到:2016-06-12 | 2016-06-29。这个结果我也可以通过这个 sql 语句得到:“SELECT MIN(holiday_begin) as holiday_begin, MAX(holiday_end) as holiday_end FROM local_lessons_holidays WHERE 1”
  • @Bonaparte 。 . .固定的。问题在于重叠逻辑。
  • 太棒了!谢谢你!我不能以新手的身份投票。现在我必须了解它是如何工作的;)
  • @Bonaparte 。 . .从最里面的子查询开始,然后逐步解决。
猜你喜欢
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 2020-12-13
  • 2021-09-28
  • 2018-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多