查询以返回缺少日期范围的第一个日期

时间:2014-05-08 13:10:48

标签: sql sql-server

使用SQL 2008 R2寻求查询帮助...我有一个包含客户端和日期字段的表。大多数客户都有大多数日期的记录,但有些人不会。 例如,我有这些数据:

CLIENTID     DT
1            5/1/14
1            5/2/14
2            5/3/14
3            5/1/14
3            5/2/14

我可以通过创建一个CLIENTID来查找每个temp table的缺失日期,其中包含该期间的所有可能日期,然后将其加入每个CLIENTIDDT选择有NULL的地方。

这是我可以轻松获得的日期范围5/1/14到5/4/14:

CLIENTID     DTMISSED
1            5/3/14
1            5/4/14
2            5/1/14
2            5/2/14
2            5/4/14
3            5/3/14
3            5/4/14

但是我想将每个连续错过的时段组合在一起,并得到每个时段的开始和长度。

例如,如果我使用日期范围5/1/14到5/4/14,我希望得到:

CLIENTID     DTSTART    MISSED
1            5/3/14     2
2            5/1/14     2
2            5/4/14     1
3            5/3/14     2

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

令人着迷的是,如何更优雅,也更有效率,这种问题可以在2012年得到解决。

首先,表格:

create table #t (CLIENTID int,    DT date)
go
insert #t values
(1,            '5/1/14'),
(1,            '5/2/14'),
(2,            '5/3/14'),
(3,            '5/1/14'),
(3,            '5/2/14')
go

create table #calendar (dt date)
go
insert #calendar values ('5/1/14'),('5/2/14'),('5/3/14'),('5/4/14')
go

这是2008年的解决方案:

;with x as (
    select *, row_number() over(order by clientid, dt) as rn
    from #calendar c
    cross join (select distinct clientid from #t) x 
    where not exists (select * from #t where c.dt=#t.dt and x.clientid=#t.clientid)
),
y as (
    select x1.*, x2.dt as x2_dt, x2.clientid as x2_clientid
    from x x1
    left join x x2 on x1.clientid=x2.clientid and x1.dt=dateadd(day,1,x2.dt)
),
z as (
    select *, (select sum(case when x2_dt is null then 1 else 0 end) from y y2 where y2.rn<=y.rn) as grp
    from y
)
select clientid, min(dt), count(*)
from z
group by clientid, grp
order by clientid

将其与2012年比较:

;with x as (
    select *, row_number() over(order by dt) as rn
    from #calendar c
    cross join (select distinct clientid from #t) x 
    where not exists (select * from #t where c.dt=#t.dt and x.clientid=#t.clientid)
),
y as (
    select x1.*, sum(case when x2.dt is null then 1 else 0 end) over(order by x1.clientid,x1.dt) as grp
    from x x1
    left join x x2 on x1.clientid=x2.clientid and x1.dt=dateadd(day,1,x2.dt)
)
select clientid, min(dt), count(*)
from y
group by clientid, grp
order by clientid