SQL Server:递归聚合信息

时间:2014-04-26 11:03:18

标签: sql-server recursion aggregate

我遇到了一个问题,我希望以递归方式从树中聚合数据。例如,我的任务列表如下所示:

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')

我希望id 3的任务如下:

id   name       status           completiondate       startdate
3    vacuum     'not done'       NULL                 '2013-12-01'

并且此结果将汇总到id 1:

id   name       status           completiondate       startdate
1    clean     'not done'        NULL                 '2013-12-01'

和id 2:

id   name       status           completiondate       startdate
2    wash      'completed'       '2014-02-01'         '2014-01-01'

逻辑是,如果所有"子任务" (子)已完成状态,然后取MAX(completiondate),否则为null。并且startdate将是所有孩子的MIN(startdate)

有没有人知道如何进行?我尝试了一个递归的CTE,但它并没有那么顺利。它可以达到几个级别,所以我想我必须从底部开始汇总?

祝你好运

1 个答案:

答案 0 :(得分:1)

递归CTE和一些有创意的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