0

I am stuck on a query in Postgres and am getting pretty frustrated. I have a table called scores with three columns:

score, user_id and date

And I want to get the average of all users last 5 scores. This query doesn't exactly get me that:

SELECT user_id, 
       ROUND( AVG( score )::numeric, 2) as sc_avg
FROM 
(SELECT ROW_NUMBER() OVER (PARTITION BY user_id) AS r,
    sc.*
    from mg.scores sc
WHERE score IS NOT NULL
ORDER BY date DESC) AS x
WHERE x.r >= 5
GROUP BY user_id;

Is there a better way to limit the last 5 jobs per user?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Slamice
  • 693
  • 1
  • 9
  • 25
  • 5
    You need to add the `ORDER BY date DESC` to the `over()` clause, otherwise the row_number() doesn't return what you think (btw: `date` is a *horrible* name for a column) –  Nov 11 '13 at 09:30

1 Answers1

1

As a_horse commented, the ORDER BY clause has to go into the window function.
And since your order is descending, it needs to be <= instead of >=:

SELECT user_id, round(avg(score)::numeric, 2) AS sc_avg
FROM  (
   SELECT *
        , row_number() OVER (PARTITION BY user_id ORDER BY date DESC) AS rn
   FROM   mg.scores
   WHERE  score IS NOT NULL
   ) AS x
WHERE  x.rn <= 5
GROUP  BY user_id;

If date can be NULL, use ORDER BY date DESC NULLS LAST. See:

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228