Reputation: 257
I got a problem where I want to aggregate data from a tree recursively. For example I have my tasklist that looks like the following:
CREATE TABLE tasks (
id int,
parentid int,
name varchar(256),
status varchar(32),
completiondate varchar(32),
startdate varchar(32)
);
INSERT INTO tasks VALUES (1, NULL, 'clean', NULL, NULL, NULL)
INSERT INTO tasks VALUES (2, NULL, 'wash', NULL, NULL, NULL)
-- insert subtasks
INSERT INTO tasks VALUES (3, 1, 'vacuum', NULL, NULL, NULL)
INSERT INTO tasks VALUES (4, 3, 'vacuum floor', 'completed', '2013-12-01', '2013-12-01')
INSERT INTO tasks VALUES (5, 3, 'vacuum stairs', 'not done', NULL, NULL)
INSERT INTO tasks VALUES (6, 1, 'windows', 'completed', '2014-02-01', '2014-01-01')
INSERT INTO tasks VALUES (7, 2, 'white clothes', 'completed', '2014-02-01', '2014-01-01')
INSERT INTO tasks VALUES (8, 2, 'colored clothes', 'completed', '2014-02-01', '2014-01-01')
And I want the task with id 3 to be like the following:
id name status completiondate startdate
3 vacuum 'not done' NULL '2013-12-01'
and this result would be aggregated up to id 1:
id name status completiondate startdate
1 clean 'not done' NULL '2013-12-01'
and for id 2:
id name status completiondate startdate
2 wash 'completed' '2014-02-01' '2014-01-01'
The logic is that if all "subtasks" (children) are status completed then take MAX(completiondate)
, else null. And startdate would be MIN(startdate)
of all children.
Does anyone have any clue of how to proceed? I tried with a recursive CTE but it didn't go so well. It can be up to several levels, so I guess I have to start from the bottom and aggregate up?
Best regards
Upvotes: 0
Views: 141
Reputation: 10098
A recursive CTE, and some creative SUM():
;with x as (
select *, id as root_id, name as root_name
from tasks
--where parentid is null
where id = 3
union all
select t.*, x.root_id, x.root_name
from tasks t
inner join x on t.parentid=x.id
),
y as (
select root_id, root_name, sum(case when status='not done' then 1 else 0 end) as status,
min(startdate) AS startdate, max(completiondate) AS completiondate
from x
group by root_id, root_name
)
select root_id, root_name, case when status = 0 then 'completed' else 'not done'end as status,
startdate, case when status = 0 then completiondate else null end
from y
Upvotes: 1