You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用CTE在SQL Server中生成类似MS Project的任务清单(含层级计算与权重汇总)

CTE在SQL Server中生成类似MS Project的任务清单(含层级计算与权重汇总)

嘿,我完全懂你想要的效果——把SQL Server里的树形任务表,转换成像MS Project那样带层级缩进、自动汇总父任务权重的清单对吧?这刚好可以用递归CTE来实现,我给你一步步拆解解决方案。

核心思路

我们需要完成两个关键目标:

  • 递归遍历任务树,计算每个任务的层级,同时生成路径保证排序符合树形结构
  • 从叶子节点往上汇总权重,给未设置权重的父任务自动计算子任务的权重总和

完整SQL代码

WITH TaskHierarchy AS (
    -- 锚点成员:获取所有根任务(无父节点的任务)
    SELECT 
        task_id,
        task_name,
        task_weight,
        task_parent,
        1 AS task_level, -- 根节点层级设为1
        CAST(task_id AS VARCHAR(MAX)) AS task_path -- 记录任务路径,用于后续排序和权重汇总
    FROM task
    WHERE task_parent IS NULL

    UNION ALL

    -- 递归成员:遍历所有子任务,继承父任务的层级和路径
    SELECT 
        t.task_id,
        t.task_name,
        t.task_weight,
        t.task_parent,
        th.task_level + 1 AS task_level,
        th.task_path + '>' + CAST(t.task_id AS VARCHAR(MAX)) AS task_path
    FROM task t
    INNER JOIN TaskHierarchy th ON t.task_parent = th.task_id
),
TaskWeightSummary AS (
    -- 初始化权重:有自身权重的用自身值,没有的先设为0
    SELECT 
        task_id,
        task_name,
        task_parent,
        task_level,
        task_path,
        COALESCE(task_weight, 0) AS base_weight,
        COALESCE(task_weight, 0) AS total_weight
    FROM TaskHierarchy

    UNION ALL

    -- 递归汇总权重:父任务总权重 = 自身基础权重 + 子任务的总权重
    SELECT 
        th.task_id,
        th.task_name,
        th.task_parent,
        th.task_level,
        th.task_path,
        COALESCE(th.task_weight, 0) AS base_weight,
        th.base_weight + tws.total_weight AS total_weight
    FROM TaskHierarchy th
    INNER JOIN TaskWeightSummary tws ON th.task_id = tws.task_parent
)
-- 最终输出:格式化层级显示,取最终的权重汇总结果
SELECT DISTINCT
    task_id,
    task_name,
    task_level,
    -- 用缩进模拟MS Project的层级显示效果
    REPLICATE('    ', task_level - 1) + task_name AS formatted_task_name,
    -- 规则:如果任务有自身设置的权重则显示原值,否则显示子任务汇总的权重
    CASE 
        WHEN base_weight <> 0 THEN base_weight
        ELSE total_weight
    END AS task_weight
FROM TaskWeightSummary
ORDER BY task_path;

代码详解

  1. TaskHierarchy CTE

    • 锚点成员先抓出所有根任务(task_parent IS NULL),给它们设置层级为1,路径初始化为自身ID
    • 递归成员通过关联父任务的ID,遍历所有子任务,层级在父任务基础上加1,路径追加子任务ID,完整记录每个任务的树形位置
  2. TaskWeightSummary CTE

    • 第一步先给每个任务初始化权重:如果任务自己有task_weight就用这个值,没有的话先设为0
    • 然后反向递归,把父任务的权重和子任务的总权重相加,实现从叶子到根的权重汇总
  3. 最终查询

    • DISTINCT去重(因为权重汇总的递归过程会生成多条同一任务的记录)
    • REPLICATE(' ', task_level - 1)给任务名称添加缩进,完全模拟MS Project的层级视觉效果
    • 排序时用task_path保证任务按树形结构的顺序排列,根任务在前,子任务紧跟父任务

示例结果(对应你的测试数据)

task_idtask_nametask_levelformatted_task_nametask_weight
1t11t10.10
2t22t20.07
4t43t40.04
5t53t50.03
3t32t30.03
6t61t60.01
7t72t70.01

自定义调整说明

如果你的需求是父任务的自身权重优先,不汇总子任务,只需要修改最终查询的CASE语句:

CASE 
    WHEN task_weight IS NOT NULL THEN task_weight
    ELSE total_weight
END AS task_weight

备注:内容来源于stack exchange,提问作者Mohammad Hasan Bakhtiarifar

火山引擎 最新活动