I have a large Postgres table test
from which I would like to extract consecutive sequences of no_signal
states per mobile_id
, or in other words the length of time individual mobile devices go out of service.
In the real table, records are not ordered, which I think would mean a PARTITION OVER (time, mobile_id
) statement would have to be included, in addition to a window function. Any advice on how to create a group for individual consecutive sequences, and then to take the min and max per group would be appreciated.
-- CREATE TABLE test (mobile_id int, state varchar, time timestamp, region varchar)
INSERT INTO test (mobile_id, state, time, region ) VALUES
(1, 'active', TIMESTAMP '2018-08-09 15:00:00', 'EU'),
(1, 'active', TIMESTAMP '2018-08-09 16:00:00', 'EU'),
(1, 'no_signal', TIMESTAMP '2018-08-09 17:00:00', 'EU'),
(1, 'no_signal', TIMESTAMP '2018-08-09 18:00:00', 'EU'),
(1, 'no_signal', TIMESTAMP '2018-08-09 19:00:00', 'EU'),
(1, 'active', TIMESTAMP '2018-08-09 20:00:00', 'EU'),
(1, 'inactive', TIMESTAMP '2018-08-09 21:00:00', 'EU'),
(1, 'active', TIMESTAMP '2018-08-09 22:00:00', 'EU'),
(1, 'active', TIMESTAMP '2018-08-09 23:00:00', 'EU'),
(2, 'active', TIMESTAMP '2018-08-10 00:00:00', 'EU'),
(2, 'no_signal', TIMESTAMP '2018-08-10 01:00:00', 'EU'),
(2, 'active', TIMESTAMP '2018-08-10 02:00:00', 'EU'),
(2, 'no_signal', TIMESTAMP '2018-08-10 03:00:00', 'EU'),
(2, 'no_signal', TIMESTAMP '2018-08-10 04:00:00', 'EU'),
(2, 'no_signal', TIMESTAMP '2018-08-10 05:00:00', 'EU'),
(2, 'no_signal', TIMESTAMP '2018-08-10 06:00:00', 'EU'),
(3, 'active', TIMESTAMP '2018-08-10 07:00:00', 'SA'),
(3, 'active', TIMESTAMP '2018-08-10 08:00:00', 'SA'),
(3, 'no_signal', TIMESTAMP '2018-08-10 09:00:00', 'SA'),
(3, 'no_signal', TIMESTAMP '2018-08-10 10:00:00', 'SA'),
(3, 'inactive', TIMESTAMP '2018-08-10 11:00:00', 'SA'),
(3, 'inactive', TIMESTAMP '2018-08-10 12:00:00', 'SA'),
(3, 'no_signal', TIMESTAMP '2018-08-10 13:00:00', 'SA')
The output that I am aiming for would be something like this:
mobile_id start_time end_time diff_time region
1 2018-08-09 17:00:00 2018-08-09 19:00:00 120 EU
2 2018-08-10 01:00:00 2018-08-10 01:00:00 0 EU
2 2018-08-10 03:00:00 2018-08-10 06:00:00 180 EU
3 2018-08-10 09:00:00 2018-08-10 10:00:00 60 SA
3 2018-08-10 13:00:00 2018-08-10 13:00:00 0 SA
The following code does not produce the desired result as groups are not correctly created:
select mobile_id, region,
least(extract(epoch from max(time) - min(time)), 0) as diff
from (select t.*,
count(*) filter (where state = 'no_signal) over (partition by mobile_id, region order by time) as grp
from t
) t
group by mobile_id, region, grp;