SQL查询 - 如何只聚合没有滞后或超前的连续时段?

时间:2013-06-16 19:34:50

标签: sql sql-server-2008-r2 group-by self-join

我仍然是我英语的新手和借口。你看我有两个人有不同的时间段,如果它们是连续的,我想汇总这些时期。我不知道如何使用例如与下一行相关的min()max()函数或比较日期之前的行。或者有更简单的方法来解决这个问题?我只有没有滞后和引导功能的SQL Server 2008 R2。

示例数据:

DECLARE @Table TABLE( 
    PersonID INT, 
    FROM    date, 
    TO date 
)

INSERT INTO @Table SELECT 1,'2011-01-01','2011-04-30'
INSERT INTO @Table SELECT 1,'2011-05-01','2011-08-31'
INSERT INTO @Table SELECT 1,'2011-09-01','2011-12-31'
INSERT INTO @Table SELECT 1,'2012-01-01','2012-03-31'

INSERT INTO @Table SELECT 2,'2011-03-01','2011-06-30'
INSERT INTO @Table SELECT 2,'2011-07-01','2011-10-31'
INSERT INTO @Table SELECT 2,'2013-01-01','2013-04-30'
INSERT INTO @Table SELECT 2,'2013-05-01','2013-08-31'

我期待这样的事情并特别注意PersonID 2:

 PersonID FROM TO 
 1 , 2011-01-01 , 2012-03-31
 2 , 2011-03-01 , 2011-10-31
 2 , 2013-01-01 , 2013-08-31

1 个答案:

答案 0 :(得分:1)

这是一个难以解决的问题,使用累积总和lag()lead()会更容易。你仍然可以做这项工作。我更喜欢使用相关子查询来表达它。

逻辑首先确定哪些记录通过重叠连接到“下一个”记录。以下查询使用此逻辑来定义OverlapWithPrev

      select *
      from (select t.*,
                   (select top 1 1
                    from t t2
                    where t2.personid = t.personid and
                          t2.fromd < t.fromd and
                          t2.tod >= dateadd(d, -1, t.fromd)
                    order by t2.fromd
                   ) as OverlapWithPrev
            from t
           ) t

如果有前一条记录,则会显示1的值;如果没有,则会显示NULL

然后使用此信息,查询然后为每个记录查找 next 记录,该记录与前一个记录不重叠(并且在同一个人身上)。如果有一系列重叠记录,则所有记录都具有相同的下一条记录,下一条记录用于聚合。

以下是完整查询:

with tp as 
     (select *
      from (select t.*,
                   (select top 1 1
                    from t t2
                    where t2.personid = t.personid and
                          t2.fromd < t.fromd and
                          t2.tod >= dateadd(d, -1, t.fromd)
                    order by t2.fromd
                   ) as OverlapWithPrev
            from t
           ) t
     )
select personid, min(fromd) as fromd, max(tod) as tod
from (select tp.*,
             (select top 1 fromd
              from tp tp2
              where tp2.OverlapWithPrev is null and
                    tp2.personid = tp.personid and
                    tp2.fromd > tp.fromd
             ) as NextFromD
      from tp
     ) tp
group by personid, NextFromD;

Here是一个SQLFiddle来展示它是如何工作的。