I have two tables that have a parent/child relationship, where one record in the parent table may correspond to N records in the child. Both tables have an amount column that I want to aggregate in one query, so I can see the total amount for the parent and the children.
When I join the tables together, the parent amounts will be counted multiple times for each child resulting in the parent aggregate values to be incorrect.
Here is a simplified version of the problem that has the bad results and my desired results.
drop table if exists parent;
CREATE TABLE parent (
id numeric,
amount numeric,
person text
);
drop table if exists child;
CREATE TABLE child (
id numeric,
parentId numeric,
amount numeric,
person text
);
insert into parent (id, amount, person) values
(1, 5, 'P1'),
(2, 15, 'P1'),
(3, 5, 'P2'),
(4, 20, 'P2');
insert into child (id, parentId, amount) values
(1, 1, 3),
(2, 1, 5),
(3, 2, 10),
(4, 3, 6),
(5, 4, 12),
(5, 4, 8);
-- Parent is double counted for each child joined onto
select
p.person,
p.id,
sum(p.amount) as parent_sum,
sum(c.amount) as child_sum
from
parent p
left outer join child as c on
c.parentId = p.id
group by rollup (p.person, p.id)
order by (p.person, p.id)
/*
Output:
| person | id | parent_sum | child_sum |
|--------|--------|------------|-----------|
| P1 | 1 | 10 | 8 |
| P1 | 2 | 15 | 10 |
| P1 | (null) | 25 | 18 |
| P2 | 3 | 5 | 6 |
| P2 | 4 | 40 | 20 |
| P2 | (null) | 45 | 26 |
| (null) | (null) | 70 | 44 |
Desired output:
| person | id | parent_sum | child_sum |
|--------|--------|------------|-----------|
| P1 | 1 | 5 | 8 |
| P1 | 2 | 15 | 10 |
| P1 | (null) | 20 | 18 |
| P2 | 3 | 5 | 6 |
| P2 | 4 | 20 | 20 |
| P2 | (null) | 25 | 26 |
| (null) | (null) | 45 | 44 |
*/
Here is an sql fiddle showing this: http://sqlfiddle.com/#!17/c4af6/2
I think I might be able to get this to work using a window function but I am looking for a better solution that is as performant as possible. Any ideas on this?
2
Answers
You can sum first up and then join, the results
SQL Fiddle
Query 1:
Results:
Using
rollup
will get you the extra rows but I think you have to do the summary a bit manually like this:You should be able to extend the pattern to deeper levels if necessary.
https://dbfiddle.uk/CxD1n2T1