I have a table with timestamps of 5 different types of events (start, stopped, restart, aborted, and completed). The given table looks like this:
Time | EventID | Event |
---|---|---|
7:38:20 | 1 | start |
7:40:20 | 2 | stopped |
7:48:20 | 3 | restart |
7:50:20 | 4 | aborted |
8:00:20 | 1 | start |
8:40:20 | 5 | completed |
8:58:20 | 1 | start |
9:00:15 | 4 | aborted |
I would like to determine the following and display it:
- Duration of individual Wash –> From (start or restart) to (stopped or aborted or completed)
- Duration of Wash Cycle –> From (start) to (aborted or completed)
- Duration of total wash time –> Sum of all individual wash in a Wash cycle
- Duration of idle time –> Wash Cycle duration – total wash time duration
So the table should look something like the following:
Time | EventID | Event | Duration of individual Wash | Duration of Wash Cycle | Duration of total wash time | Duration of idle time |
---|---|---|---|---|---|---|
7:38:20 | 1 | start | 0:02:00 | 0:12:00 | 0:04:00 | 0:08:00 |
7:40:20 | 2 | stopped | NULL | NULL | NULL | NULL |
7:48:20 | 3 | restart | 0:02:00 | NULL | NULL | NULL |
7:50:20 | 4 | aborted | NULL | NULL | NULL | NULL |
8:00:20 | 1 | start | 0:40:00 | 0:40:00 | 0:01:55 | 0:00:00 |
8:40:20 | 5 | completed | NULL | NULL | NULL | NULL |
8:58:20 | 1 | start | 0:01:55 | 0:01:55 | 0:01:55 | 0:00:00 |
9:00:15 | 4 | aborted | NULL | NULL | NULL | NULL |
So far I was able to get the duration of individual Wash and the duration of Wash Cycle by joining two table (one with only start, abort, and complete; the other with all events). I am stuck on the last two columns. I’m not sure how to approach this problem efficiently without using a while loop or counter of some sort. Would love some pointers.
Here are my code so far:
SELECT IndivWash.DateTimeStamp as 'Event TimeStamp' ,IndivWash.EventIDNo AS 'Event ID Number' ,IndivWash.EventDesc AS 'Event Description' -- for the duration of the WASH ---------------------------------------------------- ,CASE WHEN (IndivWash.EventIDNo = '1' OR IndivWash.EventIDNo = '3') AND (LEAD(IndivWash.EventIDNo) OVER (ORDER BY IndivWash.DateTimeStamp) = '2' OR LEAD(IndivWash.EventIDNo) OVER (ORDER BY IndivWash.DateTimeStamp) = '4' OR LEAD(IndivWash.EventIDNo) OVER (ORDER BY IndivWash.DateTimeStamp) = '5') AND LEAD(IndivWash.EventIDNo) OVER (ORDER BY IndivWash.DateTimeStamp) <> IndivWash.EventIDNo THEN DATEDIFF(s, IndivWash.DateTimeStamp, LEAD(IndivWash.DateTimeStamp) OVER (ORDER BY IndivWash.DateTimeStamp)) ELSE NULL END AS 'Duration of individual Wash' -- For the duration of the CYCLE ---------------------------------------------------- ,CASE WHEN WashCycle.EventIDNo = '1' AND LEAD(WashCycle.EventIDNo) OVER (ORDER BY WashCycle.DateTimeStamp) <> WashCycle.EventIDNo AND (LEAD(WashCycle.EventIDNo) OVER (ORDER BY WashCycle.DateTimeStamp) = '4' OR LEAD(WashCycle.EventIDNo) OVER (ORDER BY WashCycle.DateTimeStamp) = '5') THEN DATEDIFF(s, WashCycle.DateTimeStamp, LEAD(WashCycle.DateTimeStamp) OVER (ORDER BY WashCycle.DateTimeStamp)) ELSE NULL END AS 'Duration of Wash Cycle' -- ---------------------------------------------------- FROM ( --FROM: table with only start, abort and complete. -- to differentiate the cycles that are not aborted SELECT TOP (1000) DateTimeStamp ,EventIDNo ,EventDesc /*----------CHANGE DATABASE HERE----------*/ FROM Washer.dbo.EventLog_vw /*----------------------------------------*/ WHERE EventIDNo IN ('1','4','5') ORDER BY DateTimeStamp ) WashCycle RIGHT JOIN ( --FROM: table with all five events SELECT TOP (1000) DateTimeStamp ,EventIDNo ,EventDesc /*----------CHANGE DATABASE HERE----------*/ FROM Washer.dbo.EventLog_vw /*----------------------------------------*/ WHERE EventIDNo IN ('1','2','3','4','5') ORDER BY DateTimeStamp ) IndivWash ON WashCycle.DateTimeStamp=IndivWash.DateTimeStamp
Advertisement
Answer
Try this example based on precalculating cycles IDs CycleStartId
and CycleRestartId
:
SELECT *, CASE WHEN EventID IN (1, 3) THEN DATEDIFF(SS, MIN(Time) OVER (PARTITION BY CycleRestartId), MAX(Time) OVER (PARTITION BY CycleRestartId) ) END AS DurIndSec, CASE WHEN EventID IN (1) THEN DATEDIFF(SS, MIN(Time) OVER (PARTITION BY CycleStartId), MAX(Time) OVER (PARTITION BY CycleStartId) ) END AS DurSec, CASE WHEN EventId = 1 THEN SUM(CASE WHEN EventId = 1 THEN 0 ELSE TimeDiff END) OVER (PARTITION BY CycleStartId) END AS TotalWashSec, CASE WHEN EventId = 1 THEN SUM(COALESCE(StopIdle, 0)) OVER (PARTITION BY CycleStartId) END AS DurIdleSec FROM ( SELECT *, DATEDIFF(SS, LAG(Time, 1, Time) OVER (ORDER BY Time), Time) as TimeDiff, SUM(CASE WHEN EventID = 1 THEN 1 ELSE 0 END) OVER (ORDER BY Time) AS CycleStartId, SUM(CASE WHEN EventID IN (1, 3) THEN 1 ELSE 0 END) OVER (ORDER BY Time) AS CycleRestartId, CASE WHEN LAG(EventId, 1, EventId) OVER (ORDER BY Time) = 2 THEN DATEDIFF(SS, LAG(Time, 1, Time) OVER (ORDER BY Time), Time) END AS StopIdle FROM events ) t
Here the reports are shown in seconds. If you need to format them as time, then you can use the following expression:
CONVERT(varchar(8), DATEADD(SS, <Int in seconds>, '0:00:00'), 114)