WITH data as (
select time::timestamp as time, value from values
('2020-03-10 9:50', 1 ),
('2020-03-10 9:51', 3 ),
('2020-03-10 9:52', 1 ),
('2020-03-10 9:53', 2 ),
('2020-03-10 9:54', 0 ),
('2020-03-10 9:55', 0 ),
('2020-03-10 9:56', 1 ),
('2020-03-10 9:57', 3 ),
('2020-03-10 9:58', 2 ),
('2020-03-10 9:59', 3 ),
('2020-03-10 10:00', 2 ),
('2020-03-10 10:01', 2 ),
('2020-03-10 10:02', 0 ),
('2020-03-10 10:03', 3 ),
('2020-03-10 10:04', 1 ),
('2020-03-10 10:05', 1 ),
('2020-03-10 10:06', 1 )
s( time, value)
)
select
a.time
,a.value
,min(trig_time)over(partition by reset_time_group order by time) as first_trigger_time
,iff(a.time=first_trigger_time, datediff('minute', first_trigger_time, reset_time_group), null) as trig_duration
from (
select d.time
,d.value
,iff(d.value>=3,d.time,null) as trig_time
,iff(d.value=0,d.time,null) as reset_time
,max(time)over(order by time ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING) as max_time
,coalesce(lead(reset_time)ignore nulls over(order by d.time), max_time) as lead_reset_time
,coalesce(reset_time,lead_reset_time) as reset_time_group
from data as d
) as a
order by time;
this gives the results you seem to expect/describe..
TIME VALUE FIRST_TRIGGER_TIME TRIG_DURATION
2020-03-10 09:50:00.000 1
2020-03-10 09:51:00.000 3 2020-03-10 09:51:00.000 3
2020-03-10 09:52:00.000 1 2020-03-10 09:51:00.000
2020-03-10 09:53:00.000 2 2020-03-10 09:51:00.000
2020-03-10 09:54:00.000 0 2020-03-10 09:51:00.000
2020-03-10 09:55:00.000 0
2020-03-10 09:56:00.000 1
2020-03-10 09:57:00.000 3 2020-03-10 09:57:00.000 5
2020-03-10 09:58:00.000 2 2020-03-10 09:57:00.000
2020-03-10 09:59:00.000 3 2020-03-10 09:57:00.000
2020-03-10 10:00:00.000 2 2020-03-10 09:57:00.000
2020-03-10 10:01:00.000 2 2020-03-10 09:57:00.000
2020-03-10 10:02:00.000 0 2020-03-10 09:57:00.000
2020-03-10 10:03:00.000 3 2020-03-10 10:03:00.000 3
2020-03-10 10:04:00.000 1 2020-03-10 10:03:00.000
2020-03-10 10:05:00.000 1 2020-03-10 10:03:00.000
2020-03-10 10:06:00.000 1 2020-03-10 10:03:00.000
So how it works is we find the times of triggering, and the time of resets, then the max_time is worked out, for the last row edge case. After that we find the next reset_time forwards, and use the max_time if there is none, and then select the current reset time or prior lead_reset_time, for the work you are doing here this steps could be ignored, as your data cannot trigger and reset of the same row. And given we are doing the math on the trigger row, the reset row knowing which group it was apart of doesn't matter.
Then we break into a new select layer, as we have reached snowflakes limit for nested/interrelated SQL, and do a min across the reset_group to find the first trigger time, which we then compare to the row time and do a date diff on.
Of side note date_diff is a little naive in it's math, and '2020-01-01 23:59:59' '2020-01-02 00:00:01' are 2 seconds apart, but that are 1 minute apart and 1 hour apart and 1 day, because the function casts the timestamps to the selected unit (and truncates) and then differences those results..
To get the final batch having the value 4 as asked for in the request, alter the lead_reset_time line to:
,coalesce(lead(reset_time)ignore nulls over(order by d.time), dateadd('minute', 1, max_time)) as lead_reset_time
to move this max_time forward by one minute, if your wanted to assume outside of having data in the future time that existing row state of 10:06 is valid for 1 minute. Which is not how I would do it... but there the code you want..