【问题标题】:Calculate downtime计算停机时间
【发布时间】:2023-03-10 02:54:01
【问题描述】:

我想计算一些进程的停机时间。

我的数据可能如下所示:

Proces    ID     StartTime             EndTime  
A         1      24-07-2018 00:00:00   24-07-2018 00:02:54
A         2      24-07-2018 00:00:16   24-07-2018 00:02:55
A         3      24-07-2018 11:12:42   24-07-2018 11:15:10
A         4      24-07-2018 00:00:16   24-07-2018 00:02:55

在此示例中,ID 1、2 和 4 重叠,但停机时间应仅为 00.00.00 到 00.02.55 加上 ID 3 的停机时间。

我不知道如何比较所有时间,只让它使用重叠时间一次。

如果不清楚,再问!

我希望有人可以帮助我。

【问题讨论】:

    标签: sql-server downtime


    【解决方案1】:

    我认为最好在 TSQL 之外处理这项业务,例如,在您的应用程序中,您可以获得每一天并为每分钟使用一个位数组,并计算每个重叠范围内的最小和最大时间。 这在 tsql 中非常复杂,我认为每个解决方案都有性能问题。

    【讨论】:

    • 可以按照kodyaz.com/t-sql/… 的建议创建日期和时间间隔表,但这个解决方案似乎很原始
    【解决方案2】:

    可以使用自连接解决如下

    select t.process, sum(datediff(second, t.StartTime, t.EndTime))
    from
    (
      select distinct d1.process, min(d2.StartTime) StartTime, max(d2.EndTime) EndTime
      from data d1
      left join data d2 on d2.EndTime > d1.StartTime and d2.StartTime < d1.EndTime
      group by d1.process, d1.id
    ) t
    group by t.process
    

    DBFiddle DEMO

    但是,大数据的性能可能很差。至少(process, id, endtime)(process, id, starttime) 上的索引应该可用。

    【讨论】:

    • @Eralper 你能发送带有这些数据的 dbfiddle 演示吗?谢谢
    • 对不起,当我在 DBFiddler 上执行时,我看到它验证了我的情况
    【解决方案3】:

    您能否尝试使用更多数据进行 SQL 查询

    请尝试为不同的流程创建示例数据

    此查询汇总按进程分组的停机时间,您可以从聚合 SELECT 语句(这是最后一个查询)中删除进程以计算总体停机时间。甚至将 GroupId 添加到每个重叠停机时间链的停机时间列表中

    请查看SQL Queries for Overlapping Time Periods 上的 SQL 教程,其中详细解释了解决方案

    ;with rawdata as (
        select
            Process, id, StartTime, EndTime,
            ROW_NUMBER() over (partition by Process order by StartTime, EndTime) as rn
        from Processes
    ), cte as (
        select
            Process, StartTime, EndTime, rn, 1 as GroupId
        from rawdata
        where rn = 1
    
        union all
    
        select
            p1.Process,
            case 
            when (p1.starttime between p2.starttime and p2.endtime) then p2.starttime
            when (p2.starttime between p1.starttime and p1.endtime) then p1.starttime
            when (p1.starttime < p2.starttime and p1.endtime > p2.endtime) then p1.starttime
            when (p1.starttime > p2.starttime and p1.endtime < p2.endtime) then p2.starttime
            else p2.starttime
            end as StartTime, 
    
            case 
            when (p1.EndTime between p2.starttime and p2.endtime) then p2.EndTime
            when (p2.endtime between p1.starttime and p1.endtime) then p1.endtime
            when (p1.starttime < p2.starttime and p1.endtime > p2.endtime) then p1.endtime
            when (p1.starttime > p2.starttime and p1.endtime < p2.endtime) then p2.endtime
            else p2.endtime
            end as EndTime, 
    
            p2.rn,
            case when
                (p1.starttime between p2.starttime and p2.endtime) or
                (p1.endtime between p2.starttime and p2.endtime) or
                (p1.starttime < p2.starttime and p1.endtime > p2.endtime) or
                (p1.starttime > p2.starttime and p1.endtime < p2.endtime) 
            then
                p1.GroupId
            else 
                (p1.GroupId+1)
            end as GroupId
        from cte p1
        inner join rawdata p2
            on p1.Process = p2.Process and
               (p1.rn+1) = p2.rn
    )
    select 
        Process,
        sum(datediff(second, StartTime, EndTime)) totalDownTime
    from (
        select
            Process, GroupId, min(StartTime) StartTime, max(EndTime) EndTime
        from cte
        group by Process, GroupId
    ) t
    group by Process
    

    输出如下

    希望有用,

    【讨论】:

    • 代码有效,但是否可以在没有表格的情况下制作?我必须把它放到 Tableau 中,它不接受带有表的查询。
    • 您的意思是排除 CTE 表达式吗?它接受子选择吗?事实上,CTE 表达式是一个递归表达式。所以不可能省略递归 CTE 并实现其他解决方案。
    • 您可以使用上面的代码创建一个 SQL 视图。然后对于画面,您可以参考这个附加视图
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多