SQL Server查询将顺序日期分组

时间:2012-09-19 08:34:06

标签: sql tsql sql-server-2008-r2

我有一个名为Absence Details的表,我想对连续日期进行分组。这是数据

EID        AbsenceType  AbsenceStartDate               AbsenceEndDate
769     Holiday     2012-06-25  00:00:00.000            2012-06-25 23:59:59.000
769     Holiday     2012-06-26  00:00:00.000            2012-06-26 23:59:59.000
769     Holiday     2012-09-03  00:00:00.000            2012-09-03 23:59:59.000
769     Holiday     2012-09-04  00:00:00.000            2012-09-04 23:59:59.000
769     Holiday     2012-09-05  00:00:00.000            2012-09-05 23:59:59.000
769     Holiday     2012-09-06  00:00:00.000            2012-09-06 23:59:59.000
769     Holiday     2012-09-07  00:00:00.000            2012-09-07 23:59:59.000

我想要的结果是

EID     AbsenceType AbsenceStartDate          AbsenceEndDate
769     Holiday     2012-06-25  00:00:00.000         2012-06-26 23:59:59.000
769     Holiday     2012-09-03  00:00:00.000         2012-09-07 23:59:59.000

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:4)

我简化了您的方案以隔离主要问题。让我们在这张表中填补空白:

with ns as (
select 1 as n union
select 2 as n union
select 3 as n union
select 8 as n union    --gap
select 9 as n )
select * 
into #ns
from ns;

现在,您期望得到的结果是:

ini fi 
--- -- 
1   3  
8   9  

为了得到这个结果,我按照这种方式按摩数据:首先我用开始和结束时段创建两个视图,然后我加入两个视图以获得最终结果。请注意,我自己连接表以查找开始和结束时段:

with 
inis as                                     -- identifying start periods
(
   select n1.n
   from #ns n1
   left outer join #ns n2 
       on n1.n = n2.n + 1
   where n2.n is null
   ),
fis as                                      -- identifying ends periods
( 
   select n1.n 
   from #ns n1
   left outer join #ns n2 
       on n1.n = n2.n - 1
   where n2.n is null
   )  
select inis.n as ini, min( fis.n ) as fi    -- joining starts and ends
from inis 
inner join fis 
  on inis.n <= fis.n
group by inis.n
;

您可以将此技术传输到数据和数据类型。如果您有任何问题翻译查询可以自由询问。

Check query and results.

答案 1 :(得分:4)

这是适合我的解决方案。

SELECT EID, AbsenceType, MIN(AbsenceStartDate) AS AbsenceStartDate, MAX(AbsenceEndDate) AS AbsenceEndDate
FROM (SELECT EID, AbsenceType, AbsenceStartDate, AbsenceEndDate,
      DATEADD(dd, - ROW_NUMBER() OVER (PARTITION BY EID, AbsenceType ORDER BY EID,AbsenceStartDate), AbsenceStartDate)
      FROM AbsenceDetails
      GROUP BY EID,AbsenceType,AbsenceStartDate,AbsenceEndDate
      ) a(EID, AbsenceType, AbsenceStartDate, AbsenceEndDate, Grp)
GROUP BY EID, AbsenceType, Grp;

答案 2 :(得分:1)

我会这样做:

  1. 确定缺席日期的顺序列表。

    SELECT
        ad1.EID, ad1.StartDate, ad2.EndDate
    FROM 
        AbsenceDetails ad1
        JOIN AbsenceDetails ad2
        ON ad1.EID = ad2.EID
    WHERE
        DATEDIFF(ss, ad1.EndDate, ad2.StartDate) = 1
    

    结果如下:

    769 2012-06-25 00:00:00.000 2012-06-26 23:59:59.000
    769 2012-09-03 00:00:00.000 2012-09-04 23:59:59.000
    769 2012-09-04 00:00:00.000 2012-09-05 23:59:59.000
    769 2012-09-05 00:00:00.000 2012-09-06 23:59:59.000
    769 2012-09-06 00:00:00.000 2012-09-07 23:59:59.000
    
  2. 遍历列表并确定每个延伸的开始和结束持续时间。最好在应用层完成。

答案 3 :(得分:0)

如果我正确理解了您的问题,您希望在记录中找到连续的时间间隔 主要问题是确定实际构成连续时间间隔的内容:
如果你正在寻找工作缺席而不是

的任何序列
date1.09:00 to date1.18:00  
date2.09:00 to date2.18:00  

其中date2下一个工作日date1可以被认为是连续的。

在您的情况下,它相对容易,但您无法在单个查询中执行此操作。至少我现在想不出办法。

P.S。 “podiluska”建议的“Islands and Gaps”算法将帮助您在单个查询/存储过程中编写它。