求助:为主任务与子任务生成连续唯一TaskId的SQL实现
解决方案:为主任务和子任务生成连续关联的TaskId
核心思路
要实现主TaskId连续、子TaskId紧跟所属主TaskId的需求,不能单纯依赖全局ROW_NUMBER(),而是需要先计算每个主任务及其子任务的总数量,再通过累计求和确定每个主任务的起始ID,最后为子任务分配后续连续ID。
SQL实现方案
假设你的数据库结构如下:
MainTasks:主任务表,包含Id(主键)、Title等字段SubTasks:子任务表,包含Id(主键)、MainTaskId(关联主任务)、Title等字段
以下是完整的SQL查询代码:
WITH MainTaskCounts AS ( SELECT mt.Id AS MainTaskId, mt.Title, -- 统计当前主任务的总任务数(自身1条 + 关联子任务数) 1 + COUNT(st.Id) AS TotalTasks FROM MainTasks mt LEFT JOIN SubTasks st ON mt.Id = st.MainTaskId GROUP BY mt.Id, mt.Title ), MainTaskStartIds AS ( SELECT MainTaskId, Title, TotalTasks, -- 计算当前主任务的起始TaskId:前面所有主任务的总任务数之和 + 1 COALESCE(SUM(TotalTasks) OVER(ORDER BY MainTaskId ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) + 1 AS StartTaskId FROM MainTaskCounts ORDER BY MainTaskId ), MainTasksWithTaskId AS ( SELECT StartTaskId AS TaskId, MainTaskId AS OriginalTaskId, Title, NULL AS ParentTaskId -- 补充Gantt需要的其他字段:StartDate, EndDate, Duration等 FROM MainTaskStartIds ), SubTasksWithTaskId AS ( SELECT -- 子任务的TaskId = 所属主任务的起始ID + 子任务的排序序号 mts.StartTaskId + ROW_NUMBER() OVER(PARTITION BY st.MainTaskId ORDER BY st.Id) AS TaskId, st.Id AS OriginalTaskId, st.Title, mts.StartTaskId AS ParentTaskId -- 补充Gantt需要的其他字段:StartDate, EndDate, Duration等 FROM SubTasks st INNER JOIN MainTaskStartIds mts ON st.MainTaskId = mts.MainTaskId ) -- 合并主任务和子任务结果,按TaskId排序 SELECT * FROM MainTasksWithTaskId UNION ALL SELECT * FROM SubTasksWithTaskId ORDER BY TaskId;
代码逻辑说明
- MainTaskCounts:统计每个主任务包含的总任务数(自身1条加上关联的子任务数量)。
- MainTaskStartIds:使用窗口函数
SUM() OVER()计算每个主任务的起始TaskId,第一个主任务的起始ID为1,后续主任务的起始ID为前面所有主任务总任务数之和加1。 - MainTasksWithTaskId:将主任务的起始ID作为其TaskId,ParentTaskId设为
NULL(表示无父任务)。 - SubTasksWithTaskId:为每个子任务分配TaskId,规则是所属主任务的起始ID加上子任务在该主任务下的排序序号,ParentTaskId设为主任务的TaskId。
Syncfusion Blazor Gantt 适配
C#实体类定义
根据Gantt图表的要求,定义对应的任务实体:
public class GanttTask { public int TaskId { get; set; } public string Title { get; set; } public int? ParentTaskId { get; set; } // 根据Gantt需求添加其他字段:StartDate, EndDate, Duration, Progress等 }
API端点实现
在你的后端API中执行上述SQL,将结果映射到实体类后返回给前端:
using Dapper; using Microsoft.AspNetCore.Mvc; using System.Data.SqlClient; [ApiController] [Route("api/[controller]")] public class GanttTasksController : ControllerBase { private readonly IConfiguration _configuration; public GanttTasksController(IConfiguration configuration) { _configuration = configuration; } [HttpGet] public async Task<IActionResult> GetTasks() { var sql = @" -- 粘贴上面的完整SQL语句 "; using var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection")); var tasks = await connection.QueryAsync<GanttTask>(sql); return Ok(tasks); } }
期望输出示例
以你描述的5个主任务场景为例,最终输出的TaskId序列如下:
| TaskId | Title | ParentTaskId |
|---|---|---|
| 1 | 主任务1 | NULL |
| 2 | 子任务1-1 | 1 |
| 3 | 子任务1-2 | 1 |
| 4 | 子任务1-3 | 1 |
| 5 | 主任务2 | NULL |
| 6 | 子任务2-1 | 5 |
| 7 | 子任务2-2 | 5 |
| 8 | 主任务3 | NULL |
| 9 | 主任务4 | NULL |
| 10 | 主任务5 | NULL |
内容的提问来源于stack exchange,提问作者M.Bouabdallah
相关产品推荐
相关产品推荐

