You can run a window functions on the result of aggregate function on the same query level. It's just much simpler to use a subquery in this case:
SELECT *, sum(count_registered_users) OVER (ORDER BY month, week, day) AS running_sum
FROM (
SELECT extract(month FROM registration_time)::int AS month
, extract(week FROM registration_time)::int%4+1 AS week
, extract(day FROM registration_time)::int AS day
, count(*) AS count_registered_users
FROM loyalty.v_user
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3
) sub;
I also fixed the syntax for expression computing week
. extract()
returns double precision
, but the modulo operator %
does not accept double precision
numbers. I cast all three to integer
while being at it.
Like @a_horse commented, you cannot use positional references in the ORDER BY
clause of a window function (unlike in the ORDER BY
clause of the query).
However, you cannot use over (order by registration_time)
either in this query, since you are grouping by month
, week
, day
. registration_time
is neither aggregated nor in the GROUP BY
clause as would be required. At that stage of the query evaluation, you cannot access the column any more.
You could repeat the expressions of the first three SELECT
items in the ORDER BY
clause to make it work:
SELECT extract(month FROM registration_time)::int AS month
, extract(week FROM registration_time)::int%4+1 AS week
, extract(day FROM registration_time)::int AS day
, count(*) AS count_registered_users
, sum(count(*)) OVER (ORDER BY
extract(month FROM registration_time)::int
, extract(week FROM registration_time)::int%4+1
, extract(day FROM registration_time)::int) AS running_sum
FROM loyalty.v_user
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3;
But that seems rather noisy. (Performance would be good, though.)
Aside: I do wonder about the purpose behind week%4+1
... The whole query might be simpler.
Related: