Reputation: 1
I would like to create a graph for an application based on data in a postgresql DB. Therefore, I would like to create the average of the last X hours (e.g. 2 hours) of my value for a variable timespan (e.g. Every 10 minutes) for a total timeframe of Y hours (e.g. 8 hours).
Image: https://i.ibb.co/C8v1mXD/Bildschirmfoto-2019-09-03-um-11-52-51.png
My postgreSQL DB has a, id, a value and a timestamp column. I tried a lot to work with "group by" and "over" but unfortunately I did not achieve my goal. Maybe some of you are so nice and able to help me?
Image: https://i.ibb.co/sKpYCbJ/Bildschirmfoto-2019-09-03-um-12-03-42.png
Upvotes: 0
Views: 529
Reputation: 74605
If you're on PG11+ then ranged window functions may help you:
SELECT
avg(t.average_me) OVER(ORDER BY t.timestamp_col RANGE BETWEEN INTERVAL '3 hour' PRECEDING AND CURRENT ROW) as a
FROM yourtable t;
If you have rows with a timestamp_col
then for every row R this will calculate the average of the average_me
for all rows between R's timestamp_col and a date 10 hours before it. You can move the window too:
SELECT
avg(t.average_me) OVER(ORDER BY t.timestamp_col RANGE BETWEEN INTERVAL '3 hour' PRECEDING AND INTERVAL '2 hour' PRECEDING) as a
FROM yourtable t;
This will calc, for a row R having a timestamp_col of 2000-01-01 12:00:00
, the average of all rows whose timestamp_col is between 2000-01-01 9:00:00
and 2000-01-01 10:00:00
Update after my comment (untested):
SELECT x.* FROM(
SELECT
CASE WHEN kind = avgpoint' THEN
avg(t.average_me) OVER(ORDER BY t.timestamp_col RANGE BETWEEN INTERVAL '2 hour' PRECEDING AND INTERVAL '1 hour' PRECEDING)
END as a
FROM
(
--your data
SELECT 'datarow' as kind, average_me, timestamp_col
FROM yourtable;
UNION ALL
--your checkpoints, every 15 minutes from 10h ago to now
SELECT 'avgpoint', null, g.v
FROM generate_series(
now()-'10 hours'::interval,
now(),
'15 minute'::interval
) as g(v)
) t
) x
WHERE x.kind = 'avgpoint'
It inserts a bunch of 15 minute intervals into the data stream, with a different kind(so it can be detected). For every 'avgpoint' kind row the AVG()OVER() looks back at the data between 2 hours and 1 hour ago and averages it. This maens that every 15 minutes you get the previous previous hour average: at noon, you get the avg from 10am to 11am. At 12:15pm you get 10:15 to 11:15 etc
Upvotes: 1
Reputation: 1399
What do you think about this :
with myFictiveTable as (
select row_number() over () id ,* from (
select generate_series(now()-'3 days'::interval,now(),'10 minutes'::interval) "timestamp"
,(random()*100)::int ftz_1
) a
)
select t0,t1,avg(ftz_1) from (
select t0,COALESCE(lead(t0) over (ORDER BY t0),now()) t1 from (
select generate_series(now()-'8 hours'::interval,now(),'2 hours'::interval) t0
) a
) mytimeLaps
join myFictiveTable on ("timestamp">=t0 and "timestamp"<t1)
group by t0,t1
Upvotes: 0