Reputation: 388
I want to know the difference between two averages of value
, where each average is filtered by a condition isCool
to be either True
or False
, and the final result grouped by town
and season
, e.g.
table
| id | value | isCool | town | season |
|----|-------|--------|--------|--------|
| 0 | 1 | True | TownA | spring |
| 1 | 2 | False | TownA | winter |
| 2 | 3 | True | TownB | spring |
| 3 | 4 | False | TownA | winter |
| 4 | 5 | False | TownB | spring |
| 5 | 6 | True | TownB | winter |
I want to end up with the table:
| category | difference_of_is_cool_averages |
|----------|--------------------------------|
| TownA | 2 | <-- ABS(1 - (2 + 4)/2)
| TownB | 0.5 | <-- ABS(5 - (3 + 6)/2)
| spring | 3 | <-- ABS(5 - (3 + 1)/2)
| winter | 3 | <-- ABS(6 - (4 + 2)/2)
I have attempted this but my PostgreSQL skills are limited and I did not get far at all, unfortunately. I tried
SELECT
AVG(value), town
(SELECT id, value, town, season
FROM table
WHERE isCool = 'True') AS TableSummary1
GROUP BY town;
but this is far from what I want. Is someone able to help please? Is this even possible with PostgreSQL?
Upvotes: 1
Views: 1219
Reputation: 6140
Here Union All
will help you. Simply calculate the difference of average once by grouping town
then by grouping season
and union them. You can write your query like below:
select
town "Category",
round(abs(avg(value) filter (where iscool='t') - avg(value) filter (where iscool='f')),2) "difference_of_is_cool_averages"
from town
group by town
union all
select
season,
round(abs(avg(value) filter (where iscool='t') - avg(value) filter (where iscool='f')),2)
from town
group by season
Upvotes: 1
Reputation: 222582
You can unpivot, and then compute the difference between the two conditional averages of each group:
select x.category,
abs(avg(t.value) filter(where not t.iscool) - avg(t.value) filter(where t.iscool)) diff
from mytable t
cross join lateral (values (town), (season)) as x(category)
group by x.category
If you want to be able to order the resultset as showed in the desired results, then we need to keep track of the original column:
select x.category,
abs(avg(t.value) filter(where not t.iscool) - avg(t.value) filter(where t.iscool)) diff
from mytable t
cross join lateral (values (town, 1), (season, 2)) as x(category, grp)
group by x.category, x.grp
order by x.grp
category | diff :------- | ---------------------: TownB | 0.5000000000000000 TownA | 2.00000000000000000000 winter | 3.0000000000000000 spring | 3.0000000000000000
Upvotes: 1