Selecting an average of records grouped by 5 minute periods

后端 未结 3 472
离开以前
离开以前 2021-01-16 04:06

I\'m having a slight issue. I have a PostgreSQL table with such format

time (datetime)     | players (int) | servers (int)
----------------------------------         


        
相关标签:
3条回答
  • 2021-01-16 04:20

    Try this, it should group minutes 0-4, 5-9, 10-14 and so on...

    SELECT MIN(time), AVG(Players), AVG(Servers)
    FROM MyTable t
    GROUP BY date_trunc('hour', time),
        FLOOR(datepart('minute', time)/12)
    

    EDIT: Changed the grouping to hour first and then to the Floor of minutes. I Think this should work.

    0 讨论(0)
  • 2021-01-16 04:27

    How about this?

    select datepart('year', time) as StartYear, datepart('month', time) as StartMonth,
        datepart('day', time) as StartDay, datepart('hour', time) as StartHour,
        floor(datepart('minute', time)/5)*5 as StartMinute,
        avg(case when datepart('minute', time) = floor(datepart('minute', time)/5)*5 then players else null end) as Zero,
        avg(case when datepart('minute', time) = floor(datepart('minute', time)/5)*5+1 then players else null end) as One,
        avg(case when datepart('minute', time) = floor(datepart('minute', time)/5)*5+2 then players else null end) as Two,
        avg(case when datepart('minute', time) = floor(datepart('minute', time)/5)*5+3 then players else null end) as Three,
        avg(case when datepart('minute', time) = floor(datepart('minute', time)/5)*5+4 then players else null end) as Four,
    from MyTable
    group by datepart('year', time), datepart('month', time),
        datepart('day', time), datepart('hour', time),
        floor(datepart('minute', time)/5)*5
    
    0 讨论(0)
  • 2021-01-16 04:43
    SELECT grid.t5
          ,min(t."time") AS min_time
    --    ,array_agg(extract(min FROM t."time")) AS 'players_on' -- optional
          ,avg(t.players) AS avg_players
          ,avg(t.servers) AS avg_servers
    FROM (
       SELECT generate_series(min("time")
                             ,max("time"), interval '5 min') AS t5
       FROM tbl
       ) grid
    LEFT JOIN tbl t ON t."time" >= grid.t5
                   AND t."time" <  grid.t5 +  interval '5 min'
    GROUP  BY grid.t5
    ORDER  BY grid.t5;
    

    Explain

    • The subquery grid produces one row for every 5 minutes from the minimum to the maximum of "time" in your table.

    • LEFT JOIN back to the table slicing data in 5-min intervals. Carefully include lower border and exclude upper border.

    • To drop 5-min-slots where nothing happened, use JOIN in place of LEFT JOIN.

    • To have your grid-times start at 0:00, 5:00 etc, round down the min("time") in generate_series().

    More explanation in these related answers:
    Group by data intervals
    PostgreSQL: running count of rows for a query 'by minute'

    Aside: I wouldn't use time as identifier. It's a reserved word in standard SQL and a function / type name in Postgres.

    0 讨论(0)
提交回复
热议问题