Reputation: 11
I have a few questions about a table I'm trying to make in Postgres. The following table is my input:
id | area | count | function |
---|---|---|---|
1 | 100 | 20 | living |
1 | 200 | 30 | industry |
2 | 400 | 10 | living |
2 | 400 | 10 | industry |
2 | 400 | 20 | education |
3 | 150 | 1 | industry |
3 | 150 | 1 | education |
I want to group by id
and get the dominant function
based on max
area
. With summing up the rows for area and count. When area is equal it should be based on max count, when area and count is equal it should be based on prior function (i still have to decide if education is prior to industry or vice versa). So the result should be:
id | area | count | function |
---|---|---|---|
1 | 300 | 50 | industry |
2 | 1200 | 40 | education |
3 | 300 | 2 | industry |
I tried a lot of things and maybe it's easy, but i don't get it. Can someone help to get the right SQL?
Upvotes: 1
Views: 1261
Reputation: 76551
This is how you get the function
for each group based on id
:
select id, function
from yourtable yt1
left join yourtable yt2
on yt1.id = yt2.id and yt1.area < yt2.area
where yt2.area.id is null;
(we ensure that no yt2 exists that would be of the same id but of higher areay)
This would work nicely, but you might have several max areas with different values. To cope with this isue, let's ensure that exactly one is chosen:
select id, max(function) as function
from yourtable yt1
left join yourtable yt2
on yt1.id = yt2.id and yt1.area < yt2.area
where yt2.area.id is null
group by id;
Now, let's join
this to our main table;
select yourtable.id, sum(yourtable.area), sum(yourtable.count), t.function
from yourtable
join (
select id, max(function) as function
from yourtable yt1
left join yourtable yt2
on yt1.id = yt2.id and yt1.area < yt2.area
where yt2.area.id is null
group by id
) t
on yourtable.id = t.id
group by yourtable.id;
Upvotes: 0
Reputation: 13049
Use a scalar sub-query for "function".
select t.id, sum(t.area), sum(t.count),
(
select "function"
from the_table
where id = t.id
order by area desc, count desc, "function" desc
limit 1
) as "function"
from the_table as t
group by t.id order by t.id;
Upvotes: 1
Reputation: 1269873
One method uses row_number()
and conditional aggregation:
select id, sum(area), sum(count),
max(function) over (filter where seqnum = 1) as function
from (select t.*,
row_number() over (partition by id order by area desc) as seqnum
from t
) t
group by id;
Another method uses ``distinct on`:
select id, sum(area) over (partition by id) as area,
sum(count) over (partition by id) as count,
function
from t
order by id, area desc;
Upvotes: 1
Reputation: 1210
you can use sum as window function:
select distinct on (t.id)
id,
sum(area) over (partition by id) as area,
sum(count) over (partition by id) as count,
( select function from tbl_test where tbl_test.id = t.id order by count desc limit 1 ) as function
from tbl_test t
Upvotes: 0