如何在SQL Server中对按重叠时间分组的持续时间求和

时间:2018-08-10 09:44:23

标签: sql-server

我正在尝试在SQL Server 2008中创建一个存储的proc。

我有一个“ Timings”表(可能有成千上万条记录):

StaffID | MachineID | StartTime          | FinishTime
1       | 1         | 01/01/2018 12:00   | 01/01/18 14:30
2       | 1         | 01/01/2018 12:00   | 01/01/18 13:00
3       | 2         | 01/01/2018 12:00   | 01/01/18 13:00
3       | 2         | 01/01/2018 13:00   | 01/01/18 14:00
4       | 3         | 01/01/2018 12:00   | 01/01/18 12:30
5       | 3         | 01/01/2018 11:00   | 01/01/18 13:30

这显示每个员工在每台机器上工作了多长时间。

我想生成如下结果表:

MachineID | StaffQty | TotalMins
1         | 1        | 90
1         | 2        | 60
2         | 1        | 120
3         | 1        | 120    
3         | 2        | 30    

这将显示每台机器只有一个人使用多少分钟,每台机器有2个人使用了多少分钟,等等。

通常,我会发布到目前为止已经尝试过的内容,但是我的所有尝试似乎都已经很遥远了,我认为没有什么意义。 显然,我将非常感谢您提供一个完整的解决方案,但即使在正确的方向上稍作改动,我也将不胜感激。

2 个答案:

答案 0 :(得分:2)

我认为这可以回答您的问题:

declare @t table (StaffID int, MachineID int, StartTime datetime2,FinishTime datetime2)
insert into @t(StaffID,MachineID,StartTime,FinishTime) values
(1,1,'2018-01-01T12:00:00','2018-01-01T14:30:00'),
(2,1,'2018-01-01T12:00:00','2018-01-01T13:00:00'),
(3,2,'2018-01-01T12:00:00','2018-01-01T12:30:00')

;With Times as (
    select MachineID,StartTime as Time from @t
    union
    select MachineID,FinishTime from @t
), Ordered as (
    select
        *,
        ROW_NUMBER() OVER (PARTITION BY MachineID ORDER BY Time) rn
    from Times
), Periods as (
    select
        o1.MachineID,o1.Time as StartTime,o2.Time as FinishTime
    from
        Ordered o1
            inner join
        Ordered o2
            on
                o1.MachineID = o2.MachineID and
                o1.rn = o2.rn - 1
)
select
    p.MachineID,
    p.StartTime,
    MAX(p.FinishTime) as FinishTime,
    COUNT(*) as Cnt,
    DATEDIFF(minute,p.StartTime,MAX(p.FinishTime)) as TotalMinutes
from
    @t t
        inner join
    Periods p
        on
            p.MachineID = t.MachineID and
            p.StartTime < t.FinishTime and
            t.StartTime < p.FinishTime
group by p.MachineID,p.StartTime

结果:

MachineID   StartTime                   FinishTime                  Cnt         TotalMinutes
----------- --------------------------- --------------------------- ----------- ------------
1           2018-01-01 12:00:00.0000000 2018-01-01 13:00:00.0000000 2           60
1           2018-01-01 13:00:00.0000000 2018-01-01 14:30:00.0000000 1           90
2           2018-01-01 12:00:00.0000000 2018-01-01 12:30:00.0000000 1           30

希望您能看到每个CTE在做什么。唯一可能无法完全为您提供所需结果的地方是,一个人的FinishTime是否与同一台机器上的另一个人的StartTime完全相等。希望在真实数据中应该很少见。

答案 1 :(得分:1)

对于Sql server 2012+

请提及您的Sql服务器版本。

尝试将我的脚本与其他示例数据一起使用。 如果无法正常工作,请发布其他示例数据。

我认为我的脚本可以解决其他测试方案。

create table #temp(StaffID int,MachineID int,StartTime datetime,FinishTime datetime)

insert into #temp VALUES

(1, 1,'01/01/2018 12:00','01/01/18 14:30')

,(2, 1,'01/01/2018 12:00','01/01/18 13:00')

,(3, 2,'01/01/2018 12:00','01/01/18 12:30')

;

WITH CTE

AS (

SELECT t.*

,t1.StaffQty

,datediff(MINUTE, t.StartTime, t.FinishTime) TotalMinutes

FROM #temp t

CROSS APPLY (

SELECT count(*) StaffQty

FROM #temp t1

WHERE t.machineid = t1.machineid

AND (

t.StartTime >= t1.StartTime

AND t.FinishTime <= t1.FinishTime

)

) t1

)

SELECT MachineID

,StaffQty

,TotalMinutes - isnull(LAG(TotalMinutes, 1) OVER (

PARTITION BY t.MachineID ORDER BY t.StartTime

,t.FinishTime

), 0)

FROM cte t

 
drop table #temp

Sql server 2008

;

WITH CTE
AS (
SELECT t.*
,t1.StaffQty
,datediff(MINUTE, t.StartTime, t.FinishTime) TotalMinutes
,ROW_NUMBER() OVER (
PARTITION BY t.machineid ORDER BY t.StartTime
,t.FinishTime

) rn
FROM #temp t
CROSS APPLY (
SELECT count(*) StaffQty
FROM #temp t1
WHERE t.machineid = t1.machineid
AND (
t.StartTime >= t1.StartTime
AND t.FinishTime <= t1.FinishTime
)

) t1
)

SELECT t.MachineID
,t.StaffQty
,t.TotalMinutes - isnull(t1.TotalMinutes, 0) TotalMinutes
FROM cte t
OUTER APPLY (
SELECT TOP 1 TotalMinutes
FROM cte t1
WHERE t.MachineID = t1.machineid
AND t1.rn < t.rn
ORDER BY t1.rn DESC
) t1