I'm trying to calculate the duration a list of devices are in a specific state for each state. Each state will not repeat for that device in the list.
I have it working for 1 device, but can't get the group / order by to work to process all the devices and return a set of rows per device.
example data
CREATE TABLE telemetry (device character varying ,time timestamptz, state int);
INSERT INTO telemetry (device, time, state) values
( 'Device_001', '2021-07-03 11:28:50', 3),
( 'Device_001', '2021-07-03 11:28:56', 0),
( 'Device_001', '2021-07-03 11:29:01', 1),
( 'Device_001', '2021-07-03 11:45:22', 0),
( 'Device_001', '2021-07-03 11:45:43', 3),
( 'Device_001', '2021-07-03 11:45:53', 1),
( 'Device_001', '2021-07-03 13:00:48', 0),
( 'Device_002', '2021-07-03 11:28:41', 3),
( 'Device_002', '2021-07-03 11:28:46', 0),
( 'Device_002', '2021-07-03 11:28:51', 3),
( 'Device_002', '2021-07-03 11:28:56', 0),
( 'Device_002', '2021-07-03 11:29:01', 1),
( 'Device_002', '2021-07-03 11:29:20', 3),
( 'Device_002', '2021-07-03 11:29:26', 0),
desired result:
deviceid total state1 state2 state3 state4
Device_001 5518 26 5476 0 16
Device_002 5500 14 5445 10 31
...
single function example with more data:
http://www.sqlfiddle.com/#!17/4e8f0/1
with t as (
SELECT device,
time,
lead(time) over (order by time) - time as duration,
state
from telemetry
where device = 'Device_001'
order by time asc
)
select
min(t.device) as DeviceId, -- get first row value
extract(epoch from (sum(t.duration))) as "total",
extract(epoch from (sum(t.duration * (t.state = 0)::int))) as "state1",
extract(epoch from (sum(t.duration * (t.state = 1)::int))) as "state2",
extract(epoch from (sum(t.duration * (t.state = 2)::int))) as "state3",
extract(epoch from (sum(t.duration * (t.state = 3)::int))) as "state4"
from t;
with t as (
SELECT device,
time,
lead(time) over (Partition by device order by time) - time as duration,
state
from telemetry
order by device, time asc
)
select
--min(t.device) as DeviceId, -- get first row value
t.device,
extract(epoch from (sum(t.duration))) as "total",
extract(epoch from (sum(t.duration * (t.state = 0)::int))) as "state1",
extract(epoch from (sum(t.duration * (t.state = 1)::int))) as "state2",
extract(epoch from (sum(t.duration * (t.state = 2)::int))) as "state3",
extract(epoch from (sum(t.duration * (t.state = 3)::int))) as "state4"
from t
group by t.device
order by t.device;
http://www.sqlfiddle.com/#!17/46edf2/13
with thanks to determine duration of certain state of a device in table with multiple devices