I need to calculate percentages of various dimensions in a table. I'd like to simplify things by using window functions to calculate the denominator, however I am having an issue because the numerator has to be an aggregate as well.
As a simple example, take the following table:
create temp table test (d1 text, d2 text, v numeric);
insert into test values ('a','x',5), ('a','y',5), ('a','y',10), ('b','x',20);
If I just want to calculate the share of each individual row out of d1, then windowing functions work fine:
select d1, d2, v/sum(v) over (partition by d1)
from test;
"b";"x";1.00
"a";"x";0.25
"a";"y";0.25
"a";"y";0.50
However, what I need to do is calculate the overall share for the sum of d2 out of d1. The output I am looking for is this:
"b";"x";1.00
"a";"x";0.25
"a";"y";0.75
So I try this:
select d1, d2, sum(v)/sum(v) over (partition by d1)
from test
group by d1, d2;
However, now I get an error:
ERROR: column "test.v" must appear in the GROUP BY clause or be used in an aggregate function
I'm assuming this is because it is complaining that the window function is not accounted for in the grouping clause, however windowing functions cannot be put in the grouping clause anyway.
This is using Greenplum 4.1, which is a fork of Postgresql 8.4 and shares the same windowing functions. Note that Greenplum cannot do correlated subqueries.
Do you need to do it all with window functions? Sounds like you just need to group the result you have by
d1
andd2
and then sum the sums:That gives me this:
I think what you are actually looking for is this:
Produces the requested result.
Window functions are applied after aggregate functions. The outer
sum()
insum(sum(v))
is a window function in this example and is attached to theOVER ...
clause, while the innersum()
is an aggregate.Effectively the same as:
Or (without CTE):
Or @Mu's variant.
Aside: Greenplum introduced correlated subqueries with version 4.2. See release notes.