Search code examples
mysqlsqlsummaxaverage

Calculate average per day based on the difference of the values


I have a table:

value updated_at ID
5 2022-1-1 12:00:00 1
10 2022-1-1 12:00:30 2
20 2022-1-1 12:02:30 3

What I want to do is to get an average based on the updated_at column difference, and the values of course.

So, I guess the formula should be:

(sumof((value2 - value1) * (date2 - date1))) / (dateLast - dateFirst) where 1 and 2 means for each two rows when we traverse from the first to the last item. eg for this table we'll have:

First and second row: (value2 - value1) * (date2 - date1) = (10 - 5) * (30 (seconds)) = 150

for second and third row: (20 - 10) * 120 = 1200

So the result is:

(1200 + 150) / (2022-1-1 12:02:30 - 2022-1-1 12:00:00) = 9

I probably can get this working with a self JOIN on ID and ID + 1 and I also can do the diff of last and first date, but I can't do them both in the same query! I have no idea how to do that, is this even possible to be done in a single query?


Update

My MySql version is 5.6


Solution

  • For MySql 8.0+ you can use LAG() window function to get each row's previous values and then aggregate:

    WITH cte AS (
      SELECT *,
             value - LAG(value) OVER (ORDER BY updated_at) dif_value,
             UNIX_TIMESTAMP(updated_at) - UNIX_TIMESTAMP(LAG(updated_at) OVER (ORDER BY updated_at)) dif_time
      FROM tablename
    )
    SELECT SUM(dif_value * dif_time) / 
           (UNIX_TIMESTAMP(MAX(updated_at)) - UNIX_TIMESTAMP(MIN(updated_at))) result 
    FROM cte;
    

    For previous versions and if there are no gaps between the ids, use a self join:

    SELECT SUM(dif_value * dif_time) / 
           (UNIX_TIMESTAMP(MAX(updated_at)) - UNIX_TIMESTAMP(MIN(updated_at))) result 
    FROM (
      SELECT t1.*,
             t1.value - t2.value dif_value,
             UNIX_TIMESTAMP(t1.updated_at) - UNIX_TIMESTAMP(t2.updated_at) dif_time
      FROM tablename t1 LEFT JOIN tablename t2
      ON t1.ID = t2.ID + 1
    ) t; 
    

    See the demo.