Question

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

Était-ce utile?

La solution

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top