2013-04-03 96 views
2

使用SQL Server 2008 R2,结合连续日期范围

我试图日期范围组合成给出的最大日期范围是一个结束日期旁边以下的开始日期。

该数据是关于不同的就业。一些员工可能已经结束了工作,并在晚些时候重新加入。这些应该算作两种不同的雇用(例如ID 5)。有些人有不同类型的就业机会,一个接一个地工作(结束日期和开始日期),在这种情况下,它应该被视为总共一个就业机会(例如ID 30)。

尚未结束的就业期限结束日期为null。

一些例子大概是启发:

declare @t as table (employmentid int, startdate datetime, enddate datetime) 

insert into @t values 
(5, '2007-12-03', '2011-08-26'), 
(5, '2013-05-02', null), 
(30, '2006-10-02', '2011-01-16'), 
(30, '2011-01-17', '2012-08-12'), 
(30, '2012-08-13', null), 
(66, '2007-09-24', null) 

-- expected outcome 
EmploymentId StartDate EndDate 
5   2007-12-03 2011-08-26 
5   2013-05-02 NULL 
30   2006-10-02 NULL 
66   2007-09-24 NULL 

我一直在尝试不同的“孤岛和隙”技术,但一直没能破解这一个。

+0

不应'startDate == endDate'为适当的重叠?否则将有24小时不明。 – MaxH

+0

这将是存储过程,是吗?或通过查询限制? – orrollo

+0

@MaxH:实际上,日期时间用作日期。所以重叠是可以的。 –

回答

6

您在使用日期'31211231'时看到的奇怪位是处理您的“无结束日期”情景的非常大的日期。我假设你不会有许多日期范围,每个员工,所以我用一个简单的递归公用表表达式来结合范围。

为了使运行速度更快,起始锚点查询只保留那些将而不是链接到之前范围(每名员工)的日期。剩下的只是树木漫步日期范围和增加范围。最后的GROUP BY只保留每个启动ANCHOR(employmentid,startdate)组合的最大日期范围。


SQL Fiddle

MS SQL Server 2008的架构设置

create table Tbl (
    employmentid int, 
    startdate datetime, 
    enddate datetime); 

insert Tbl values 
(5, '2007-12-03', '2011-08-26'), 
(5, '2013-05-02', null), 
(30, '2006-10-02', '2011-01-16'), 
(30, '2011-01-17', '2012-08-12'), 
(30, '2012-08-13', null), 
(66, '2007-09-24', null); 

/* 
-- expected outcome 
EmploymentId StartDate EndDate 
5   2007-12-03 2011-08-26 
5   2013-05-02 NULL 
30   2006-10-02 NULL 
66   2007-09-24 NULL 
*/ 

查询1

;with cte as (
    select a.employmentid, a.startdate, a.enddate 
    from Tbl a 
left join Tbl b on a.employmentid=b.employmentid and a.startdate-1=b.enddate 
    where b.employmentid is null 
    union all 
    select a.employmentid, a.startdate, b.enddate 
    from cte a 
    join Tbl b on a.employmentid=b.employmentid and b.startdate-1=a.enddate 
) 
    select employmentid, 
      startdate, 
      nullif(max(isnull(enddate,'32121231')),'32121231') enddate 
    from cte 
group by employmentid, startdate 
order by employmentid 

Results

| EMPLOYMENTID |      STARTDATE |      ENDDATE | 
----------------------------------------------------------------------------------- 
|   5 | December, 03 2007 00:00:00+0000 | August, 26 2011 00:00:00+0000 | 
|   5 |  May, 02 2013 00:00:00+0000 |      (null) | 
|   30 | October, 02 2006 00:00:00+0000 |      (null) | 
|   66 | September, 24 2007 00:00:00+0000 |      (null) | 
+0

优秀!好的解决方案 –

0

用于组合所有重叠周期的修改脚本。
例如
01.01.2001-01.01.2010
05.05.2005-05.05.2015

会给一个周期:
01.01.2001-05.05.2015

tbl.enddate必须完成

;WITH cte 
    AS(
SELECT 
    a.employmentid 
    ,a.startdate 
    ,a.enddate 
from tbl a 
left join tbl c on a.employmentid=c.employmentid 
    and a.startdate > c.startdate 
    and a.startdate <= dateadd(day, 1, c.enddate) 
WHERE c.employmentid IS NULL 

UNION all 

SELECT 
    a.employmentid 
    ,a.startdate 
    ,a.enddate 
from cte a 
inner join tbl c on a.startdate=c.startdate 
    and (c.startdate = dateadd(day, 1, a.enddate) or (c.enddate > a.enddate and c.startdate <= a.enddate)) 
) 
select distinct employmentid, 
      startdate, 
      nullif(max(enddate),'31.12.2099') enddate 
from cte 
group by employmentid, startdate