用于合并连续日期并忽略非连续日期的SQL查询

时间:2015-07-13 13:50:32

标签: sql sql-server

我需要一些帮助,因为我对SQL语句不太满意......

我在数据库中有以下表格:

+------+------------+------------+
| E_ID |  FromDate  |   ToDate   |
+------+------------+------------+
|  555 | 2012-01-01 | 2012-12-31 |
|  555 | 2013-01-01 | 2013-12-31 |
|  555 | 2014-01-01 | 2014-04-30 |
|  555 | 2014-05-01 | 2014-08-15 |
|  555 | 2014-08-16 | 2014-12-31 |
|  555 | 2015-01-01 | 2015-06-25 |
|  555 | 2015-07-01 | 2015-12-31 |
+------+------------+------------+

我想合并连续的日期,按年份分组,在玩了一点后我来到这个查询:

select  E_ID
       ,FromDate = MIN(FromDate)
       ,ToDate = MAX(ToDate)
from TbTest
group by E_ID
        ,DATEPART(YEAR,FromDate)
        ,DATEPART(YEAR,ToDate)

结果几乎是我想要的:

+------+------------+------------+
| E_ID |  FromDate  |   ToDate   |
+------+------------+------------+
|  555 | 2012-01-01 | 2012-12-31 |
|  555 | 2013-01-01 | 2013-12-31 |
|  555 | 2014-01-01 | 2014-12-31 |
|  555 | 2015-01-01 | 2015-12-31 |
+------+------------+------------+

这几乎是完美的。这里的问题是,在2015年的日期,我们有重叠:

|  555 | 2015-01-01 | 2015-06-25 |
|  555 | 2015-07-01 | 2015-12-31 |

因此,而不是FromDate 2015-06-26,而是2015-07-01,所以我们有6天的“差距”。对于那些特定的情况,我想拆分它们,所以我想要的结果就是:

+------+------------+-------------+
| E_ID |  FromDate  |   ToDate    |
+------+------------+-------------+
|  555 | 2012-01-01 | 2012-12-31  |
|  555 | 2013-01-01 | 2013-12-31  |
|  555 | 2014-01-01 | 2014-12-31  |
|  555 | 2015-01-01 | 2015-06-25  |
|  555 | 2015-07-01 | 2015-12-31  |
+------+------------+-------------+

简而言之,我需要连续几天才能合并,而不会缺少一天。

PS:我现在在想,ToDate有时会像9999-12-31这样,所以我的小组实际上是不正确的......

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

我很抱歉,因为我没有时间测试下面的代码,但我认为这个想法就在这里。

with aggr as
(
select  E_ID,
        FromDate,
        ToDate,
        lev = 0
from TbTest
UNION ALL
select  T.E_ID,
       A.FromDate,
       T.ToDate,
       lev = A.lev + 1 
from TbTest T
        inner join aggr A
        on T.e_ID = A.E_ID  AND datediff(day,A.Todate,T.FromDate) = 1 
        AND DATEPART(YEAR,A.TODate) = DATEPART(YEAR,T.FromDate)
)

select E_ID, FromDate, ToDate from aggr
EXCEPT
Select AG1.E_ID, AG1.FromDate, AG1.ToDate
from aggr AG1
 inner join aggr AG2
 ON AG1.E_ID = AG2.E_ID 
    AND AG1.Fromdate >= AG2.fromdate and AG1.todate <= AG2.todate and AG1.lev < AG2.lev
Order by E_ID, Fromdate

编辑1:我修复了脚本。这是SQL Fiddle