从值的开始日期查询值的时间范围

时间:2013-09-29 21:15:45

标签: sql tsql

我有一个值表,其有效期从开始日期开始,如下所示:

select x.*
into #t
from
(select 15 as value, '2012.05.20' as start-datedate
union
select 15, '2012.06.20'
union
select 15, '2012.07.20'
union
select 16, '2012.08.20'
union
select 17, '2012.09.20'
union
select 15, '2012.11.20'
union
select 17, '2012.12.20'
) x

所以表格如下:

select * from #t order by date

value   start-date
-----------------------------
15      2012.05.20
15      2012.06.20
15      2012.07.20
16      2012.08.20
17      2012.09.20
15      2012.11.20
17      2012.12.20

我的问题是如何制作一个时间段表,其中每个值都有效。它应该是这样的:

value       start_date      end_date
15        2012.05.20       2012.08.20
16          2012.08.20  2012.09.20
17          2012.09.20  2012.11.20
15          2012.11.20  2012.12.20
17          2012.12.20  

谢谢!

2 个答案:

答案 0 :(得分:1)

不确定这是否是最佳解决方案,但认为它可以实现您所追求的目标:http://sqlfiddle.com/#!3/d41d8/21691

select value, min(startdate) start_date, nextDate end_date
from
(
  select value
  , startdate
  , (
    select min(startdate) 
    from #t t2 
    where t2.value != t1.value
    and t2.startdate > t1.startdate 
  ) nextDate
  from #t t1
) y
group by value, nextDate
order by start_date

答案 1 :(得分:0)

drop table #t

select x.*
into #t
from
(select 15 as value, cast( '2012.05.20' as date ) as startdate
union
select 15, '2012.06.20'
union
select 15, '2012.07.20'
union
select 15, '2012.11.20'
union
select 17, '2012.12.20'
union
select 17, '2012.09.20'
union
select 16, '2012.08.20'
) x

;with "cte"
as
(
    select  
        rank() over ( partition by t1."value" order by t1."startdate" ) as "rank"
        , t1."value"
        , t1."startdate"
        , ISNULL ( t2."startdate", dateadd( month, 1, cast( t1."startdate" as date ))) as "enddate"
    from #t as t1
    left join #t as t2
        on 1 = 1
        and t1."value" = t2."value"
        and datediff( month, t1."startdate", t2."startdate" ) = 1
)
, "cte2"
as
(
    select
        c1.value
        , c1."startdate" 
        , c1."enddate" 
    from 
        cte c1
    left join
        cte c2
        on 1 = 1
        and c1."rank" + 1 = c2."rank"
        and c1."value" = c2."value"
)
, "cte3"
as
(
    select
        value, startdate
    from cte2

    union all

    select
        value, enddate
    from cte2
)
, "cte4"
as
(
    select 
        * 
        , count( 1 ) over ( partition by value, startdate ) as "no"
    from 
        cte3 
)
, "cte5"
as
(
select
    row_number() over ( partition by "value" order by "startdate" ) as "rn"
    , *
from
    cte4
where
    "no" = 1
)
select
    c1."value"
    , c1."startdate"
    , c2."startdate" as "endtime"
from
    cte5 as c1
    inner join cte5 as c2
    on 
        1 = 1
        and c1."rn" + 1 = c2."rn"
        and c1."value" = c2."value"
        and c1."rn" % 2 = 1
order by
    "value"
    , "startdate"

请参阅SQL-Fiddle