sqlsql-servert-sqlview

Inserting Rows Through a View by Column


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.


Solution

  • 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)
    

    fiddle