Calculate Actual Downtime ignoring overlap in dates/times

前端 未结 2 1831
-上瘾入骨i
-上瘾入骨i 2021-01-14 16:10

I\'m trying to work out how to calculate actual downtime for various applications from data I\'m storing within a table.

At the moment I\'m just calculating the dif

相关标签:
2条回答
  • 2021-01-14 16:28

    UPDATED WITH NEW TEST CASES

    Here is one technique that calculates the unique outages and then aligns them back to the initial downtime causing the outage so that the actual and expected values match.

    DECLARE @Downtime TABLE (
        ID INT PRIMARY KEY NOT NULL IDENTITY(1,1),
        Application VARCHAR(25), 
        DowntimeStart DATETIME,
        DowntimeEnd DATETIME,
        Expected INT
    )
    
    INSERT @Downtime (Application, DowntimeStart, DowntimeEnd, Expected) VALUES -- Act/Exp
        ('Application Demo', '2014-11-20 17:31:01.467', '2014-11-20 18:01:01.243', 30) -- 30/30
        ,('Application Demo', '2014-11-28 17:59:00.987', '2014-11-28 18:09:02.167', 26) -- 10/26
        ,('Application Demo', '2014-11-28 18:00:01.403', '2014-11-28 18:25:01.443', 0) -- 25/0
        ,('Application Demo', '2014-11-29 19:13:08.580', '2014-11-30 05:30:01.763', 617) -- 617/617
        ,('Application Demo', '2014-11-30 01:55:01.953', '2014-11-30 03:54:01.730', 0)
        ,('Application Demo 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397', 3514)
        ,('Application Demo 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397', 0)
        ,('Application Demo 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397', 0) 
        ,('Application Demo 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397', 0)
        ,('Application Demo 2', '2014-12-19 23:09:01.303', '2014-12-22 09:43:01.397', 0) 
    
    SELECT
        Downtimes.Application,
        Downtimes.DowntimeStart,
        Downtimes.DowntimeEnd,
        Downtimes.Expected,
        COALESCE(Actual, 0) AS Actual
    FROM @Downtime Downtimes
        LEFT OUTER JOIN (
            SELECT DISTINCT
                D1.Application,
                MIN(CASE WHEN D1.DowntimeStart < D2.DowntimeStart THEN D1.ID ELSE D2.ID END) AS [ID],
                MIN(CASE WHEN D1.DowntimeStart < D2.DowntimeStart THEN D1.DowntimeStart ELSE D2.DowntimeStart END) AS [DowntimeStart],
                MAX(CASE WHEN D1.DowntimeEnd > D2.DowntimeEnd THEN D1.DowntimeEnd ELSE D2.DowntimeEnd END) AS [DowntimeEnd],
                DATEDIFF(MINUTE,
                    MIN(CASE WHEN D1.DowntimeStart < D2.DowntimeStart THEN D1.DowntimeStart ELSE D2.DowntimeStart END),
                    MAX(CASE WHEN D1.DowntimeEnd > D2.DowntimeEnd THEN D1.DowntimeEnd ELSE D2.DowntimeEnd END)) AS Actual
            FROM @Downtime D1
                INNER JOIN @Downtime D2
                    ON D1.Application = D2.Application
                        AND (D1.DowntimeStart BETWEEN D2.DowntimeStart AND D2.DowntimeEnd
                            OR D2.DowntimeStart BETWEEN D1.DowntimeStart AND D1.DowntimeEnd)
            GROUP BY
                D1.Application,
                D1.DowntimeStart
        ) Outages
            ON Outages.ID = Downtimes.ID
    

    And this yields the desired output:

    Application               DowntimeStart           DowntimeEnd             Expected    Actual
    ------------------------- ----------------------- ----------------------- ----------- -----------
    Application Demo          2014-11-20 17:31:01.467 2014-11-20 18:01:01.243 30          30
    Application Demo          2014-11-28 17:59:00.987 2014-11-28 18:09:02.167 26          26
    Application Demo          2014-11-28 18:00:01.403 2014-11-28 18:25:01.443 0           0
    Application Demo          2014-11-29 19:13:08.580 2014-11-30 05:30:01.763 617         617
    Application Demo          2014-11-30 01:55:01.953 2014-11-30 03:54:01.730 0           0
    Application Demo 2        2014-12-19 23:09:01.303 2014-12-22 09:43:01.397 3514        3514
    Application Demo 2        2014-12-19 23:09:01.303 2014-12-22 09:43:01.397 0           0
    Application Demo 2        2014-12-19 23:09:01.303 2014-12-22 09:43:01.397 0           0
    Application Demo 2        2014-12-19 23:09:01.303 2014-12-22 09:43:01.397 0           0
    Application Demo 2        2014-12-19 23:09:01.303 2014-12-22 09:43:01.397 0           0
    
    0 讨论(0)
  • 2021-01-14 16:30

    I had a similar problem, and I got it answered in my question How to Consolidate Blocks of Time?

    In your case, this is accomplished with a top 1 self outer apply to get the overlap, and then use either the Overlap's Start time, or if null, the normal Record's end time as the end time.

    CREATE TABLE Downtime (
        Application VARCHAR(25), 
        DowntimeStart DATETIME,
        DowntimeEnd DATETIME,
        Expected INT
    )
    
    INSERT Downtime (Application, DowntimeStart, DowntimeEnd, Expected) VALUES -- Act/Exp
        ('Application Demo', '2014-11-20 17:31:01.467', '2014-11-20 18:01:01.243', 30) -- 30/30
        ,('Application Demo', '2014-11-28 17:59:00.987', '2014-11-28 18:09:02.167', 26) -- 10/26
        ,('Application Demo', '2014-11-28 18:00:01.403', '2014-11-28 18:25:01.443', 0) -- 25/0
        ,('Application Demo', '2014-11-29 19:13:08.580', '2014-11-30 05:30:01.763', 617) -- 617/617
        ,('Application Demo', '2014-11-30 01:55:01.953', '2014-11-30 03:54:01.730', 0)
    
    
    SELECT
        Records.Application, Records.DowntimeStart, Records.DowntimeEnd, Records.Expected
      , DATEDIFF(minute, Records.DowntimeStart, COALESCE(Overlap.DowntimeStart, Records.DowntimeEnd)) AS Actual
    --  , Overlap.Application, Overlap.DowntimeStart, Overlap.DowntimeEnd -- For Verification Purposes
    FROM Downtime Records
      OUTER APPLY (
        SELECT TOP 1 Overlap.Application, Overlap.DowntimeStart, Overlap.DowntimeEnd
        FROM Downtime Overlap
        WHERE Records.Application = Overlap.Application
          AND Overlap.DowntimeStart > Records.DowntimeStart
          AND Overlap.DowntimeStart BETWEEN Records.DowntimeStart AND Records.DowntimeEnd
        ORDER BY Overlap.DowntimeStart
        ) Overlap
    

    Here's the SQLFiddle with the solution.

    0 讨论(0)
提交回复
热议问题