SQL Server 2014 合并重叠日期范围

法洛夫

我在 SQL Server 2014 数据库中有一个包含 200.000 行的表,如下所示:

CREATE TABLE DateRanges
(
     Contract VARCHAR(8),
     Sector VARCHAR(8),
     StartDate DATE,
     EndDate DATE
);

INSERT INTO DateRanges (Contract, Sector, StartDate, Enddate)
   SELECT '111', '999', '01-01-2014', '03-31-2014'
   union
   SELECT '111', '999', '04-01-2014', '06-30-2014'
   union
   SELECT '111', '999', '07-01-2014', '09-30-2014'
   union
   SELECT '111', '999', '10-01-2014', '12-31-2014'
   union
   SELECT '111', '888', '08-01-2014', '08-31-2014'
   union
   SELECT '111', '777', '08-15-2014', '08-31-2014'
   union
   SELECT '222', '999', '01-01-2014', '03-31-2014'
   union
   SELECT '222', '999', '04-01-2014', '06-30-2014'
   union
   SELECT '222', '999', '07-01-2014', '09-30-2014'
   union
   SELECT '222', '999', '10-01-2014', '12-31-2014'
   union
   SELECT '222', '666', '11-01-2014', '11-30-2014'
   UNION
   SELECT '222', '555', '11-15-2014', '11-30-2014';

如您所见,每个合同可能有多个重叠,我想要的是这样的结果

    Contract   Sector   StartDate     EndDate
    ---------------------------------------------
    111        999      01-01-2014    07-31-2014
    111        888      08-01-2014    08-14-2014
    111        777      08-15-2014    08-31-2014
    111        999      09-01-2014    12-31-2014

    222        999      01-01-2014    10-31-2014
    222        666      11-01-2014    11-14-2014
    222        555      11-15-2014    11-30-2014
    222        999      12-01-2014    12-31-2014

我不知道如何做到这一点,我在这个网站上看到的例子完全不适合我的问题。

脚后跟

这个答案使用了几种不同的技术。第一个是,它创建一个包含每个相关的表cal_date,然后cross apply使用唯一Contract值获取两个值的每个组合。第二个是例如lagrow_number确定下面评论中详述的各种事情。最后,也许是最重要的,来确定一个Contract/Sector组合何时结束和下一个开始。

回答:

--determine range of dates 
declare @bgn_dt date = (select min(StartDate) from DateRanges)
    , @end_dt date = (select max(EndDate) from DateRanges)

--use a recursive CTE to create a record for each day / Contract
; with dates as
    (
        select @bgn_dt as cal_date
        union all
        select dateadd(d, 1, a.cal_date) as cal_date
        from dates as a
        where a.cal_date < @end_dt
    )
select d.cal_date
, c.Contract
into #contract_dates
from dates as d
cross apply (select distinct Contract from DateRanges) as c
option (maxrecursion 0)

--Final Select
select f.Contract
, f.Sector
, min(f.cal_date) as StartDate
, max(f.cal_date) as EndDate
from (
    --Use the sum-over to obtain the Island Numbers
    select dr.Contract
    , dr.Sector
    , dr.cal_date
    , sum(dr.IslandBegin) over (partition by dr.Contract order by dr.cal_date asc) as IslandNbr
    from (
        --Determine if the record is the start of a new Island
        select a.Contract
        , a.Sector
        , a.cal_date
        , case when lag(a.Sector, 1, NULL) over (partition by a.Contract order by a.cal_date asc) = a.Sector then 0 else 1 end as IslandBegin
        from (
            --Determine which Contract/Date combinations are valid, and rank the Sectors that are in effect
            select cd.cal_date
            , dr.Contract
            , dr.Sector
            , dr.EndDate
            , row_number() over (partition by dr.Contract, cd.cal_date order by dr.StartDate desc) as ConractSectorRnk
            from #contract_dates as cd
            left join DateRanges as dr on cd.Contract = dr.Contract
                                      and cd.cal_date between dr.StartDate and dr.EndDate
            ) as a
        where a.ConractSectorRnk = 1
        and a.Contract is not null
        ) as dr
    ) as f
group by f.Contract
, f.Sector
, f.IslandNbr
order by f.Contract asc
, min(f.cal_date) asc

输出:

+----------+--------+------------+------------+
| Contract | Sector | StartDate  |  EndDate   |
+----------+--------+------------+------------+
|      111 |    999 | 2014-01-01 | 2014-07-31 |
|      111 |    888 | 2014-08-01 | 2014-08-14 |
|      111 |    777 | 2014-08-15 | 2014-08-31 |
|      111 |    999 | 2014-09-01 | 2014-12-31 |
|      222 |    999 | 2014-01-01 | 2014-10-31 |
|      222 |    666 | 2014-11-01 | 2014-11-14 |
|      222 |    555 | 2014-11-15 | 2014-11-30 |
|      222 |    999 | 2014-12-01 | 2014-12-31 |
+----------+--------+------------+------------+

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章