使用T-SQL,如何生成显示日期范围的结果

时间:2014-01-29 23:37:51

标签: sql sql-server-2008 tsql

使用SQL Server,如何生成显示日期范围的结果集,如下所示:

StartDate    EndDate
01/01/2014   01/04/2014
01/08/2014   01/11/2014
01/14/2014   01/15/2014

原始数据的格式为日期:

ColumnA      DateColumn
blah         01/01/2014
blah         01/02/2014
blah         01/03/2014
blah         01/04/2014
blah         01/08/2014
blah         01/09/2014
blah         01/10/2014
blah         01/11/2014
blah         01/14/2014
blah         01/15/2014

目前,我有很多查询可以做到这一点,但我想知道我是否可以用更少的代码做一些事情:

SELECT ROW_NUMBER() OVER(ORDER BY DateColumn) AS rownum,
       DateColumn
INTO #main
FROM MyTable

SELECT m1.DateColumn AS TBegin, 
       m2.DateColumn AS TEnd, 
       COALESCE(DATEDIFF(day, m2.TimePk, m1.TimePk), 0) AS Gap
INTO #Gap
FROM #main m1
LEFT OUTER JOIN #main m2
 ON m1.rownum = m2.rownum + 1
ORDER BY m1.DateColumn

SELECT ROW_NUMBER() OVER(ORDER BY i_id, TBegin) AS rownum,
       TBegin
INTO #Begin
FROM #Gap
WHERE Gap <> 1
ORDER BY TBegin

SELECT ROW_NUMBER() OVER(ORDER BY i_id, TEnd) AS rownum,
       TEnd
INTO #End
FROM (
     SELECT TEnd
     FROM #Gap
     WHERE Gap > 1
     UNION
     SELECT MAX(TBegin)
     FROM #Gap
     ) as t
ORDER BY TEnd

SELECT b.TBegin,
       e.TEnd
FROM #Begin b
INNER JOIN #End e
      ON b.i_id = e.i_id
      AND b.rownum = e.rownum
ORDER BY b.TBegin

有关如何以完全不同的方式简化或处理此问题的任何想法?

2 个答案:

答案 0 :(得分:0)

这对你有用。但它仍然相当复杂。它使用内部查询来查找每个日期的间隙之后的第一个日期。这样,属于同一组日期的所有日期都可以组合在一起。

select MIN(DateColumn) StartDate, MAX(DateColumn) EndDate from
    (select X.DateColumn, MIN(Y.DateColumn) MinOverGap from 
        (select DateColumn, ROW_NUMBER() OVER (ORDER BY DateColumn) RowNumber
        from MyTable) X
    left join 
        (select DateColumn, ROW_NUMBER() OVER (ORDER BY DateColumn) RowNumber
        from MyTable) Y
        on DATEADD(d, Y.RowNumber - 1, X.DateColumn) <> DATEADD(d, X.RowNumber -1, Y.DateColumn) AND X.DateColumn < Y.DateColumn
    group by x.DateColumn) grouped
group by MinOverGap
order by 1

答案 1 :(得分:0)

我对这些方法的处理方法是确定在它之前没有日期的第一个日期。这是一个小组的开始。然后我将其累积总和作为组标识符,并进行聚合。

SQL Server 2008没有lag或累积总和,因此我使用相关子查询:

with mt as (
      select t.*,
             (case when (select top 1 t2.dateColumn
                         from MyTable t2
                         where t2.ColumnA = t.ColumnA and
                               t2.dateColumn < t.dateColumn
                         order by t2.dateColumn desc
                        ) = dateadd(day, -1, t.datecolumn)
                   then 0
                   else 1
              end) as IsStart
      from MyTable t
     ),
     mtcum as (
      select mt.*,
             (select sum(mt2.IsStart)
              from mt mt2
              where mt2.ColumnA = mt.ColumnA and
                    mt2.dateColumn <= mt.DateColumn
             ) as grpId
      from mt
     )
select ColumnA, min(dateColumn) as StartDate, max(dateColumn) as EndDate
from mtcum
group by ColumnA, grpId;

编辑:

更简单的方法是观察日期序列和数字序列之间的差异是不变的。

select columnA, min(dateColumn) as StartDate, max(dateColumn) as EndDate
from (select mt.*, row_number() over (partition by ColumnA order by datecolumn) as seqnum
      from mytable mt
     ) t
group by columnA, dateadd(day, - seqnum, datecolumn);