Here is entry's hierarchy.
_________Milky Way (30)________
/ | \
Alpha(10) Beta(20) Delta(null)
/ \ |
Mars(7) Jupiter(3) Delta-child(44)
Parents value is a sum of it's children's values. Ex.
Alpha = Mars + Jupiter = 7 + 3 = 10
Milky Way = Alpha + Beta + Delta = 10 + 20 + null = 30
The task: recalculate parents up to the root in case any child is updated. Let's even simplify the task: select all entries up to the root with recalculated values.
Imagine that Mars is updated. Now Mars value is 2.
_________Milky Way (?)________
/ | \
Alpha(?) Beta(20) Delta(null)
/ \ |
Mars(2) Jupiter(3) Delta-child(44)
It means that all parents should be updated:
Alpha = Mars + Jupiter = 2 + 3 = 5
Milky Way = Alpha + Beta + Delta = 5 + 20 + null = 25.
Note: Delta -> Delta-child coupling is broken and it's fine. It can happen lets leave it out of scope here. 've added this sample just to be sure that it won't be counted during calculation as hierarchy can be huge enough and tehre is no task to recalculate all children leaf, just parents up to the root.
As a result of some "select .. from hierarchy.."
I'd like to receive recalculated parents' values.
Ex.
| id | name | value |
|---|---|---|
| 1 | Milky Way | 25 |
| 2 | Alpha | 5 |
Code samples with already updated Mars (sqlfiddle links are below):
Schema
CREATE TABLE hierarchy
(
id int4,
parent_id int4,
name varchar(255),
value int4
);
Values
insert into hierarchy
values
(1, null, 'Milky Way', 30),
(2, 1, 'Alpha', 10),
(3, 1, 'Beta', 20),
(4, 1, 'Delta', null),
(5, 2, 'Mars', 2),
(6, 2, 'Jupiter', 3),
(7, 4, 'Delta-child', 44);
What I have tried:
I was able to list all leafs which should be used in calculation
sqlfiddle 1WITH RECURSIVE cte AS ( SELECT h1.id, h1.parent_id, h1.name , h1.value from hierarchy h1 where h1.id = 5 UNION SELECT h2.id, h2.parent_id, h2.name , h2.value from hierarchy h2 JOIN cte cte ON (cte.parent_id = h2.parent_id or cte.parent_id = h2.id ) where cte.id != h2.id ) select * from cte order by idWhen I tried to sum values, query goes in infinite loop for some reason
sqlfiddle 2WITH RECURSIVE cte AS ( SELECT h1.id, h1.parent_id, h1.name , h1.value from hierarchy h1 where h1.id = 5 UNION SELECT h2.id, h2.parent_id, h2.name , (h2.value + cte.value) as value from hierarchy h2 JOIN cte cte ON (cte.parent_id = h2.parent_id or cte.parent_id = h2.id ) where cte.id != h2.id ) select * from cte order by idThere is one more query that I have tried, unfortunately it doesn't count sibling of parents.
sqlfiddle 3WITH RECURSIVE cte AS ( SELECT h1.id, h1.parent_id, h1.name , h1.value from hierarchy h1 where h1.parent_id = (select parent_id from hierarchy where id = 5) UNION SELECT h2.id, h2.parent_id, h2.name , cte.value as value from hierarchy h2 JOIN cte cte ON (cte.parent_id = h2.parent_id or cte.parent_id = h2.id ) where cte.id != h2.id ) select id, parent_id, name, sum(value) from cte group by id, parent_id, name order by id
I'd appreciate any assistance. :-)