在 SQL Server 中,我有一个名为任务的表,其中包含列:
任务id | 任务名称 | 任务权重 | 任务父级 |
---|---|---|---|
1, | t1 | 空 | 空 |
2 | t2 | 空 | 1 |
3 | t3 | 0.03 | 1 |
4 | t4 | 0.04 | 2 |
5 | t5 | 0.03 | 2 |
6 | t6 | 空 | 空 |
7 | t7 | 0.01 | 6 |
task_parent
列是一个外键,可能为空或与此表中的另一个task_id
相关。
我想编写一个 CTE 来在像 MS Project 这样的工作表中显示任务,其中具有一些递归子级的任务行的 task_weight 是从其子级中总结出来的,并且每个子级的级别是根据其递归父级计算的。每个孩子可能还有另一个孩子,依此类推。所以考虑这个来计算顶级权重。
架构是这样的:
CREATE TABLE TASK
(
task_id int IDENTITY(1,1) PRIMARY KEY,
task_name varchar(100),
task_weight float,
task_parent int
);
数据是这样的:
SET IDENTITY_INSERT [task] ON;
INSERT INTO task (task_id,task_name,task_weight,task_parent) VALUES
(1,'t1',null,null),
(2,'t2',null,1),
(3,'t3',0.03,1),
(4,'t4',0.04,2),
(5,'t5',0.03,2),
(6,'t6',null,null),
(7,'t7',0.01,6);
SET IDENTITY_INSERT [task] OFF;
我期望这样的结果(请考虑顺序):
任务名称 | 任务权重 | 级别 |
---|---|---|
t1 | 0.10 | 1 |
__t2 | 0.07 | 2 |
____t4 | 0.04 | 3 |
____t5 | 0.03 | 3 |
__t3 | 0.03 | 2 |
t6 | 0.01 | 1 |
__t7 | 0.01 | 2 |
with r as (
select 1 as level, task_id, task_name,
cast(0 as decimal(3, 2)) as task_weight,
cast(task_name as varchar(max)) as task_chain
from task
where task_parent is null
union all
select level + 1, t.task_id, t.task_name,
t.task_weight, concat(r.task_chain, '>', t.task_name)
from task t inner join r on r.task_id = t.task_parent
)
select
concat(replicate('__', level - 1), r.task_name) as task_name,
cumulative_weight as weight, level
from r cross apply (
select sum(task_weight) from r r2
where r2.task_chain like concat('%', r.task_chain, '%')
) as s(cumulative_weight)
order by weight desc;