MySQL合并具有重叠日期跨度的表行

MySQL合并具有重叠日期跨度的表行,mysql,sql,Mysql,Sql,我有一张临时桌子,有重叠的可用日期。这些日期可以以任何方式重叠,因为它们适用于多个可用房间 我想创建一个查询,返回一组合并的可用日期。开放日期为可用日期;关闭不可用 例如,以下数据 +------------+------------+ | opens | closes | +------------+------------+ | 2015-12-03 | 2015-12-05 | | 2016-01-08 | 2016-01-15 | | 2016-02-21 | 2016

我有一张临时桌子,有重叠的可用日期。这些日期可以以任何方式重叠,因为它们适用于多个可用房间

我想创建一个查询,返回一组合并的可用日期。开放日期为可用日期;关闭不可用

例如,以下数据

+------------+------------+
|   opens    |   closes   |
+------------+------------+
| 2015-12-03 | 2015-12-05 |
| 2016-01-08 | 2016-01-15 |
| 2016-02-21 | 2016-02-27 |
| 2016-03-13 | 2016-03-24 |
| 2016-03-31 | 2016-04-02 |
| 2016-04-06 | 2016-04-15 |
| 2016-04-21 | 2016-12-03 |
| 2015-12-03 | 2015-12-09 |
| 2016-01-03 | 2016-01-06 |
| 2016-01-16 | 2016-02-08 |
| 2016-03-01 | 2016-03-06 |
| 2016-03-10 | 2016-12-03 |
+------------+------------+
应返回:

+------------+------------+
|   opens    |   closes   |
+------------+------------+
| 2015-12-03 | 2015-12-09 |
| 2016-01-03 | 2016-01-06 |
| 2016-01-08 | 2016-01-15 |
| 2016-01-16 | 2016-02-08 |
| 2016-02-21 | 2016-02-27 |
| 2016-03-01 | 2016-03-06 |
| 2016-03-10 | 2016-12-03 |
+------------+------------+

谢谢你的帮助

一种方法是使用相关子查询:

SELECT DISTINCT
       (SELECT MIN(opens)
       FROM mytable AS t2
       WHERE t2.opens <= t1.closes AND t2.closes >= t1.opens) AS start,
       (SELECT MAX(closes)
       FROM mytable AS t2
       WHERE t2.opens <= t1.closes AND t2.closes >= t1.opens) AS end       
FROM mytable AS t1
ORDER BY opens
记录2在处理时会产生有缺陷的开始/结束间隔

下面是一个使用变量的解决方案:

SELECT MIN(start) AS start, MAX(end) AS end
FROM (
  SELECT @grp := IF(@start = '1900-01-01' OR 
                   (opens <= @end AND closes >= @start), @grp, @grp+1) AS grp,        
         @start := IF(@start = '1900-01-01', opens, 
                      IF(opens <= @end AND closes >= @start, 
                         IF (@start < opens, @start, opens), opens)) AS start,
         @end := IF(@end = '1900-01-01', closes, 
                    IF (opens <= @end AND closes >= @start, 
                      IF (@end > closes, @end, closes), closes)) AS end                 
  FROM mytable
  CROSS JOIN (SELECT @grp := 1, @start := '1900-01-01', @end := '1900-01-01') AS vars
  ORDER BY opens, DATEDIFF(closes, opens) DESC) AS t
GROUP BY grp
其想法是从最左边的打开/关闭间隔开始。变量@start、@end用于在间隔链中处理新的重叠行时以增量方式传播扩展。一旦遇到非重叠间隔,[@start-@end]将被初始化以匹配此新间隔,grp将递增1


Giorgos是网站上最好的SQL人员之一。@Mark Giorgos的查询在您的数据集上应该可以正常工作。只要根据需要更改列/表名。@TimBiegeleisen结果表明我的查询有缺陷。它在任何重叠日期间隔的组合上都不起作用。例如,它不适用于马克昨天提出的问题的样本数据。@Giorgosbetos这很讽刺,因为我对他以前的数据集的查询似乎适用于该数据集,但不适用于此问题的数据。是的,重叠的日期间隔令人讨厌。@TimBiegeleisen这是由于输入数据的高度不规则性造成的。一个通用的解决方案,处理所有可能的情况,必然比上面的查询复杂得多!我提出了一个替代解决方案,可以处理任何一组输入数据。它实际上与你的另一个问题的数据有关。
SELECT MIN(start) AS start, MAX(end) AS end
FROM (
  SELECT @grp := IF(@start = '1900-01-01' OR 
                   (opens <= @end AND closes >= @start), @grp, @grp+1) AS grp,        
         @start := IF(@start = '1900-01-01', opens, 
                      IF(opens <= @end AND closes >= @start, 
                         IF (@start < opens, @start, opens), opens)) AS start,
         @end := IF(@end = '1900-01-01', closes, 
                    IF (opens <= @end AND closes >= @start, 
                      IF (@end > closes, @end, closes), closes)) AS end                 
  FROM mytable
  CROSS JOIN (SELECT @grp := 1, @start := '1900-01-01', @end := '1900-01-01') AS vars
  ORDER BY opens, DATEDIFF(closes, opens) DESC) AS t
GROUP BY grp