Search code examples
sqlpostgresqlaveragewindow-functions

Function to get rolling average with lowest 2 values eliminated?


This is my sample data with the current_Rating column my desired output.


Date         Name    Subject         Importance    Location     Time      Rating  Current_rating
12/08/2020   David   Work            1             London       -         -       4
1/08/2020    David   Work            3             London       23.50     4       3.66
2/10/2019    David   Emails          3             New York     18.20     3       4.33
2/08/2019    David   Emails          3             Paris        18.58     4       4
11/07/2019   David   Work            1             London       -         3       4
1/06/2019    David   Work            3             London       23.50     4       4
2/04/2019    David   Emails          3             New York     18.20     3       5
2/03/2019    David   Emails          3             Paris        18.58     5       -
12/08/2020   George  Updates         2             New York     -         -       2
1/08/2019    George  New Appointments5             London       55.10     2       -

I need to use a function to get values in the current_Rating column.The current_Rating gets the previous 5 results from the rating column for each name, then eliminates the lowest 2 results, then gets the average for the remaining 3. Also some names may not have 5 results, so I will just need to get the average of the results if 3 or below, if 4 results I will need to eliminate the lowest value and average the remaining 3. Also to get the right 5 previous results it will need to be sorted by date. Is this possible? Thanks for your time in advance.


Solution

  • What a pain! I think the simplest method might be to use arrays and then unnest() and aggregate:

    select t.*, r.current_rating
    from (select t.*,
                 array_agg(rating) over (partition by name order by date rows between 4 preceding and current row) as rating_5
          from t
         ) t cross join lateral
         (select avg(r) as current_rating
          from (select u.*
                from unnest(t.rating_5) with ordinality u(r, n)
                where r is not null
                order by r desc desc
                limit 3
               ) r
         ) r