Say you have a room with an indefinite number of light bulbs, and these are turning randomly on and off. Each time a bulb is turned on and then off, a record is entered in a table with TurnedOn and TurnedOff values. How should the query look like if I am interested in how long (HH.mm.ss) was it visible in the room between two DateTime values?
e.g.
LightBulbId | TurnedOn | TurnedOff |
---|---|---|
1 | 2022-10-01 06:00:00 | 2022-10-01 11:00:00 |
2 | 2022-10-01 07:00:00 | 2022-10-01 10:00:00 |
3 | 2022-10-01 08:00:00 | 2022-10-01 09:00:00 |
4 | 2022-10-01 12:00:00 | 2022-10-01 13:00:00 |
5 | 2022-10-01 14:00:00 | 2022-10-01 15:00:00 |
So for the example above in the time period between 2022-10-01 06:00:00 and 2022-10-01 15:00:00 - 09 hours has passed and it was visible for 07 hours.
- The bulb can be on for more than 24 hours.
- One hour increments are put in the example for simplicity.
- If at least one light bulb is on, you can see in the room.
- If a Light is turned on, starting from that moment you can see in the room, and if a light is turned off starting from that moment you can not :-)
Another example with the same logic:
Say you have a machine that more than one person can work on at the same time. StartTime and EndTime is added to the table each time when a person starts and then stops working on a machine. I am interested in what was machines work time for a given time period?
CodePudding user response:
select sign(on_off) as on_off
,sum(hour_diff) as hours
from
(
select *
,datediff(second, time, lead(time) over(order by time))/3600.0 as hour_diff
,sum(case when status = 'TurnedOn' then 1 else -1 end) over(order by time) as on_off
from t
unpivot (time for status in(TurnedOn, TurnedOff)) up
) t
group by sign(on_off)
on_off | hours |
---|---|
0 | 2.000000 |
1 | 7.000000 |
CodePudding user response:
To expand on the correct answer above, this will give the results in the desired hh:mm:ss format
select
sign(on_off) as on_off,
RIGHT('0' CONVERT(VARCHAR(2),SUM(secs_diff)/3600 ),2) 'h'
RIGHT('0' CONVERT(VARCHAR(2),SUM(secs_diff)/60 ` ),2) 'm'
RIGHT('0' CONVERT(VARCHAR(2),SUM(secs_diff)`),2) 's'
from
(
select *
,datediff(second, time, lead(time) over(order by time))as secs_diff
,sum(case when status = 'TurnedOn' then 1 else -1 end) over(order by time) as on_off
from #Lights
unpivot (time for status in(TurnedOn, TurnedOff)) up
) t
group by sign(on_off)