2014-04-26 46 views
0

我遇到了一个问题,我想从树中递归聚合数据。例如,我有我的任务列表,看起来像下面这样:SQL Server:递归聚合信息

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),否则为空。并且startdate将是所有孩子的MIN(startdate)

有没有人有任何线索如何进行?我尝试了一个递归的CTE,但它并没有那么好。它可以达到几个级别,所以我想我必须从底部开始并聚合起来?

问候

回答

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 
+0

真棒!谢谢! – peter