简体   繁体   中英

MySQL get the average and sum of a columns for each x minutes of a group

I tried multiple hours to figure out a query for this but I had no luck. I don't even know if it is possible with just one query.

I have a table like this

id - server_id - players_online - performance - timestamp

This table includes about one record for each server every 5-10 minutes. The thing is, I wanna get the average performance and the sum of players_online per 20 minute interval but as the same server can occur multiple times within these 20 minutes it can corrupt the final result that I want:

  1. group by 20 min interval
  2. only keep one result per server_id per 20 min interval
  3. get the average performance and sum of players_online of all servers per 20 min interval

With ROUND(timestamp/(20*60)) I can easily group by the 20 min interval, but how do I proceed. How would you write query?

The query I tried to so far:

SELECT avg(performance) as performance, sum(playersOnline) as playersOnline, timestamp
    FROM stats_server
    GROUP BY ROUND(timestamp/(1200))

Example Data: http://www.mediafire.com/download/z629q3g38qhr46h/stats_server.sql.gz

Result (average/sum from servers for this time) :

timestamp     | performance | online players
1404757200000 | 93          | 125
1404758400000 | 92          | 120
1404759600000 | 96          | 133
1404759800000 | 93          | 168
1404751000000 | 88          | 122
1404751200000 | 94          | 134

SOLUTION:

SELECT min20 * 1200 AS timestamp, AVG( performance ) AS performance, SUM( players ) AS playersOnline
        FROM (
            SELECT serverID, FLOOR( UNIX_TIMESTAMP( timestamp ) / 1200 ) AS min20, AVG( performance ) AS performance, AVG( playersOnline ) AS players
            FROM stats_server
            GROUP BY min20, serverID
        ) tmp
        GROUP BY min20
        ORDER BY timestamp

Your problem lies with your information design. If there are 10 people online at a moment and 10 poeple online a moment later, you cannot say if there were 10 or 20 people online. It could have been the same 10 people like the moment before or 10 new people.

If you want to get the exact number of people online, you have to save information that help to distinguish your users, like IP-Adresses.

Based on your records, the only logical thing would be to fetch the maximum of people online, say

max(playersOnline)

which is at least a lower bound for the sum of players online.

SELECT min20 * 1200 AS timestamp, AVG( performance ) AS performance, SUM( players ) AS playersOnline FROM ( SELECT serverID, FLOOR( UNIX_TIMESTAMP( timestamp ) / 1200 ) AS min20, AVG( performance ) AS performance, AVG( playersOnline ) AS players FROM stats_server GROUP BY min20, serverID ) tmp GROUP BY min20 ORDER BY timestamp

If you are using MySql or SQL and the timestamp is a standard unix timestamp you are best formatting the timestamp to a date / time format to then group the results.

have a look at http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format

so for example you could change the timestamp to be DD MM YYYY HH:MM and group by that

GROUP BY server_id, DATE_FORMAT(timestamp, '%W %M %Y %H:%S')

EDIT: Think you need to group by server_id first

EDIT 2: Try the following - can't really test as the timestamps are out when using now()

SELECT serverID, avg(performance), sum(playersOnline), DATE_FORMAT(timestamp, '%W %M %Y %H:%S') FROM `stats_server` where timestamp > now()-1200 group by ROUND(timestamp/(1200)), serverID order by serverID, ROUND(timestamp/(1200)) asc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM