SQL Server:计算重叠时间跨度的总持续时间

时间:2018-04-10 01:39:08

标签: sql-server tsql

我有一个数据集,基本上是一组“任务组”及其开始和结束时间,如下所示

Group         Name              StartTime                  EndTime
---------------------------------------------------------------------
GroupA        Task1          01-01-2018T09:00        01-01-2018T11:00
GroupA        Task2          01-01-2018T10:00        01-01-2018T12:00
GroupA        Task3          01-01-2018T10:00        01-01-2018T13:00
GroupA        Task4          01-01-2018T20:00        01-01-2018T22:00

我需要计算组中任务的总持续时间(或组​​持续时间),同时考虑它们之间的重叠。例如,在上面的示例中,总组持续时间应为6小时

如何在T-SQL中实现这一目标?

2 个答案:

答案 0 :(得分:1)

这是使用自我加入的另一种选择

declare @t table ([Group] varchar(10), Name varchar(10), StartTime datetime, EndTime datetime)
insert into @t
values 
('GroupA', 'Task1', '20180101 09:00', '20180101 11:00')
, ('GroupA', 'Task2', '20180101 10:00', '20180101 12:00')
, ('GroupA', 'Task3', '20180101 10:00', '20180101 13:00')
, ('GroupA', 'Task4', '20180101 20:00', '20180101 22:00')

select
    [Group], StartTime = min(StartTime), EndTime
from (
    select
        a.[Group], a.StartTime, EndTime = max(b.EndTime)
    from 
        @t a
        left join @t b on a.[Group] = b.[Group] and a.StartTime < b.EndTime and a.EndTime > b.StartTime
    group by a.[Group], a.StartTime
) t
group by [Group], EndTime

答案 1 :(得分:0)

使用递归CTE

; with 
tbl as  -- your sample data
(
    select [Group] = 'GroupA', Name = 'Task1', StartTime = '2018-01-01 09:00', EndTime = '2018-01-01 11:00' union all
    select [Group] = 'GroupA', Name = 'Task2', StartTime = '2018-01-01 10:00', EndTime = '2018-01-01 12:00' union all
    select [Group] = 'GroupA', Name = 'Task3', StartTime = '2018-01-01 10:00', EndTime = '2018-01-01 13:00' union all
    select [Group] = 'GroupA', Name = 'Task4', StartTime = '2018-01-01 20:00', EndTime = '2018-01-01 22:00'
),
cte as  -- cte to assign rn to each row
(
    select  *, rn = row_number() over(partition by [Group] order by StartTime, EndTime)
    from    tbl
),
rcte as -- recursive cte to find grp with start and end time
(
    select  [Group], StartTime, EndTime, rn, grp = 1
    from    cte
    where   rn  = 1

    union all

    select  r.[Group], 
        StartTime   = case  when    c.StartTime between r.StartTime and r.EndTime
                    then    r.StartTime
                    else    c.StartTime
                    end,
        EndTime     = c.EndTime,
        c.rn,
        grp     = case  when    c.StartTime between r.StartTime and r.EndTime
                    then    r.grp
                    else    r.grp + 1
                    end
    from    rcte r
        inner join cte c    on  r.[Group]   = c.[Group]
                    and r.rn        = c.rn - 1
)
select  *   -- the datediff() for StartTime and EndTime is what you want
from
(
    select  *, r = row_number() over (partition by grp order by rn desc)
    from    rcte
) d
where   d.r = 1