My requirement is this: I have a view that returns a recordset where for each change in value of the DeviceStatus
column, I set the Flag
column to 1.
This way I can then calculate the total duration of that status. The problem is when the duration “overflows” into the next hour, because I would like another record with the new hour.
The query is this.
SELECT
EventTime, DeviceStatus, DeviceName,
CASE
WHEN DeviceStatus = LAG(DeviceStatus) OVER (ORDER BY EventTime)
THEN 0
ELSE 1
END AS Flag
FROM
[EventSourcing].[Fact].[Operations]
WHERE
(DeviceName LIKE 'Device%')
AND DateID in (20241129,20241130)
ORDER BY
1
A specific case is this one, where at 18:15:07 there is a state change that continues until 04:44:02 the following day
EventTime | DeviceName | DeviceStatus | Flag |
---|---|---|---|
2024-11-29 18:04:11.2361142 | DeviceB | 1000 | 0 |
2024-11-29 18:05:54.7418091 | DeviceB | 1000 | 0 |
2024-11-29 18:08:20.8451237 | DeviceB | 1000 | 0 |
2024-11-29 18:11:39.1074294 | DeviceB | 1000 | 0 |
2024-11-29 18:16:40.1076772 | DeviceB | 2000 | 1 |
!2024-11-30 03:44:55.2751548 | DeviceB | 1000 | 1 |
2024-11-29 18:08:49.8317093 | DeviceA | 1000 | 0 |
2024-11-29 18:08:57.3539314 | DeviceA | 1000 | 0 |
2024-11-29 18:09:05.1978502 | DeviceA | 1000 | 0 |
2024-11-29 18:09:08.6673125 | DeviceA | 1000 | 0 |
2024-11-29 18:09:16.1053403 | DeviceA | 2000 | 1 |
2024-11-29 18:09:27.3567976 | DeviceA | 2000 | 0 |
2024-11-29 18:09:57.3746556 | DeviceA | 2000 | 0 |
2024-11-29 18:15:07.8193011 | DeviceA | 3004 | 1 |
2024-11-30 04:44:02.7432369 | DeviceA | 2000 | 1 |
2024-11-30 04:45:21.7130785 | DeviceA | 2016 | 1 |
2024-11-30 04:46:36.8242106 | DeviceA | 2000 | 1 |
2024-11-30 04:53:58.1847945 | DeviceA | 1000 | 1 |
2024-11-30 04:56:05.6637439 | DeviceA | 1000 | 0 |
2024-11-30 04:56:28.4035914 | DeviceA | 1000 | 0 |
I wish it were like this
EventTime | DeviceName | DeviceStatus | Flag |
---|---|---|---|
2024-11-29 18:04:11.2361142 | DeviceB | 1000 | 0 |
2024-11-29 18:05:54.7418091 | DeviceB | 1000 | 0 |
2024-11-29 18:08:20.8451237 | DeviceB | 1000 | 0 |
2024-11-29 18:11:39.1074294 | DeviceB | 1000 | 0 |
2024-11-29 18:16:40.1076772 | DeviceB | 2000 | 1 |
2024-11-29 19:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-29 20:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-29 21:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-29 22:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-29 23:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-30 00:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-30 01:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-30 02:00:00.0000000 | DeviceB | 2000 | 0 |
2024-11-30 03:00:00.0000000 | DeviceB | 2000 | 0 |
!2024-11-30 03:44:55.2751548 | DeviceB | 1000 | 1 |
!2024-11-30 03:58:31.0083900 | DeviceB | 1000 | 0 |
!2024-11-30 04:00:29.9581687 | DeviceB | 1000 | 0 |
2024-11-29 18:08:49.8317093 | DeviceA | 1000 | 0 |
2024-11-29 18:08:57.3539314 | DeviceA | 1000 | 0 |
2024-11-29 18:09:05.1978502 | DeviceA | 1000 | 0 |
2024-11-29 18:09:08.6673125 | DeviceA | 1000 | 0 |
2024-11-29 18:09:16.1053403 | DeviceA | 2000 | 1 |
2024-11-29 18:09:27.3567976 | DeviceA | 2000 | 0 |
2024-11-29 18:09:57.3746556 | DeviceA | 2000 | 0 |
2024-11-29 18:15:07.8193011 | DeviceA | 3004 | 1 |
2024-11-29 19:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-29 20:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-29 21:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-29 22:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-29 23:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-30 00:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-30 01:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-30 02:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-30 03:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-30 04:00:00.0000000 | DeviceA | 3004 | 0 |
2024-11-30 04:44:02.7432369 | DeviceA | 2000 | 1 |
2024-11-30 04:45:21.7130785 | DeviceA | 2016 | 1 |
2024-11-30 04:46:36.8242106 | DeviceA | 2000 | 1 |
2024-11-30 04:53:58.1847945 | DeviceA | 1000 | 1 |
2024-11-30 04:56:05.6637439 | DeviceA | 1000 | 0 |
2024-11-30 04:56:28.4035914 | DeviceA | 1000 | 0 |
Do I necessarily have to enter records?
I wouldn't know how to do that. Thank you to anyone who can help me.
Use event time if it exists for a given hour, otherwise use generated exact hour. For Device Status we use the value from the most recent EventTime. Updated 2024-DEC-06 07:40 to use Generate_Series instead of recursive CTE. Updated 2024-DEC-09 to include DeviceName.
--Use event time if it exists for a given hour+devicename combination,otherwise use generated exact hour
with d as (
--Generate dates at 1 hour intervals for 48 hours
--Crossjoin with distinct DeviceName
SELECT DATEADD(HOUR, Hours.value -1 , '2024-11-29') dte, DeviceName
FROM GENERATE_SERIES(1,48) Hours
CROSS JOIN
(SELECT distinct DeviceName
FROM Operations) do
)
select isnull(o.EventTime,d.dte) as EventTime,
isnull(o.DeviceName, d.devicename) as devicename,
isnull(DeviceStatus,
(SELECT top 1 DeviceStatus FROM Operations WHERE eventtime < dte ORDER BY eventtime Desc)
) as DeviceStatus,
CASE WHEN o.EventTime IS NULL THEN 0
ELSE
CASE WHEN DeviceStatus = LAG(DeviceStatus) OVER (ORDER BY EventTime) THEN 0 ELSE 1 END
END AS Flag
from d
LEFT JOIN Operations o ON o.devicename=d.devicename AND d.dte=DATEADD(HH,DATEPART(HH,o.EventTime),CAST(CAST(o.EventTime AS DATE) AS DATETIME))
WHERE isnull(o.DeviceName, d.devicename) LIKE 'Device%'
AND CAST( isnull(o.EventTime,d.dte) AS DATE) in ('2024-11-29','2024-11-30')
ORDER BY devicename desc, isnull(o.EventTime,d.dte)