Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 在SQL Server中,如何对按重叠时间分组的持续时间求和_Sql Server - Fatal编程技术网

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

Sql server 在SQL Server中,如何对按重叠时间分组的持续时间求和,sql-server,Sql Server,我正在尝试在SQLServer2008中创建一个存储过程 我有一个“计时”表(可能有数千条记录): 这显示了每个工作人员在每台机器上工作的时间 我想制作一个结果表如下: MachineID | StaffQty | TotalMins 1 | 1 | 90 1 | 2 | 60 2 | 1 | 120 3 | 1 | 120 3 | 2 |

我正在尝试在SQLServer2008中创建一个存储过程

我有一个“计时”表(可能有数千条记录):

这显示了每个工作人员在每台机器上工作的时间

我想制作一个结果表如下:

MachineID | StaffQty | TotalMins
1         | 1        | 90
1         | 2        | 60
2         | 1        | 120
3         | 1        | 120    
3         | 2        | 30    
这将显示每台机器有多少分钟只有一个人使用它,每台机器有多少分钟有两个人使用它等等

通常情况下,我会发布到目前为止我已经尝试过的东西,但我所有的尝试似乎都太遥远了,我认为没有什么意义。
显然,我非常感谢能有一个完整的解决方案,但我也希望能朝着正确的方向稍微推动一下。

我想这回答了你的问题:

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

希望你能看到每个CTE都在做什么。如果一个人的
FinishTime
与另一个人在同一台机器上的
StartTime
正好相等,则这可能无法准确地给出您正在寻找的结果。希望在真实数据中是罕见的。

我想这回答了你的问题:

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

希望你能看到每个CTE都在做什么。如果一个人的
FinishTime
与另一个人在同一台机器上的
StartTime
正好相等,则这可能无法准确地给出您正在寻找的结果。希望在真实数据中是罕见的。

对于
Sql server 2012+

请说明您的Sql server版本

使用其他示例数据尝试我的脚本。 如果不起作用,请发布其他示例数据

我认为我的脚本可以用于其他测试场景

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 2012+

请说明您的Sql server版本

使用其他示例数据尝试我的脚本。 如果不起作用,请发布其他示例数据

我认为我的脚本可以用于其他测试场景

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


非常感谢。我会看一看,看看我是否能理解它是如何工作的。如果其中一个范围完全包围了其他范围,这似乎不起作用。。。我将用额外的样本数据更新我的问题,以说明我的意思。@Gravitate-如果你只关心在每个“占用”级别的使用时间,那么你可以将当前的最终结果移动到CTE中,并进行最终查询
SUM(TotalMinutes)
GROUP BY MachineID,Cnt
耶。。。我已经做到了。隐马尔可夫模型。。。我认为它不起作用,但通过我的示例数据检查,它确实起作用了。。。这一定是我做错了别的事情(或者是我没有想到的与我的实时数据有关的事情)。我会再打给你的。再次感谢你,好的。。。问题是,我删除了您的临时表,并将其替换为我的实际表。出于某种原因,当我在表的最终select中交换@t时出错。我知道这不是数据,就像我先将它插入临时表一样,没有问题。你知道为什么会这样吗?使用中间临时表可以解决问题,但如果不需要,我宁愿不使用它。再次感谢您迄今为止的帮助。谢谢。我会看一看,看看我是否能理解它是如何工作的。如果其中一个范围完全包围了其他范围,这似乎不起作用。。。我将用额外的样本数据更新我的问题,以说明我的意思。@Gravitate-如果你只关心在每个“占用”级别的使用时间,那么你可以将当前的最终结果移动到CTE中,并进行最终查询
SUM(TotalMinutes)
GROUP BY MachineID,Cnt
耶。。。我已经做到了。隐马尔可夫模型。。。我认为它不起作用,但通过我的示例数据检查,它确实起作用了。。。这一定是我做错了别的事情(或者是我没有想到的与我的实时数据有关的事情)。我会再打给你的。再次感谢你,好的。。。问题是,我删除了您的临时表,并将其替换为我的实际表。出于某种原因,当我在表的最终select中交换@t时出错。我知道这不是数据,就像我先将它插入临时表一样,没有问题。你知道为什么会这样吗?使用中间临时表可以解决问题,但如果不需要,我宁愿不使用它。再次感谢您迄今为止的帮助。谢谢。我来看看。另外,我在问题的第一行说明了我正在使用的SQL Server版本。没问题。我相信您的回答对任何使用更高版本SQL Server的有类似问题的人都会有帮助。@Gravitate,您可以查看我的SQL Server 2008版本。谢谢。我会看一看。谢谢你的帮助,但我选择了@Damien_作为不信者的答案,因为他先回答了,我发现它更容易理解。再次感谢,谢谢。我来看看。另外,我在问题的第一行说明了我正在使用的SQL Server版本。没问题。我相信您的回答对任何使用更高版本SQL Server的有类似问题的人都会有帮助。@Gravitate,您可以查看我的SQL Server 2008版本。谢谢。我会看一看。谢谢你的帮助,但我选择了@Damien_作为不信者的答案,因为他先回答了,我发现它更容易理解。再次感谢。
;

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