如何在SQL Server递归查询中使用MIN()函数聚合最小日期
在SQL Server递归CTE中从下到上聚合最小日期的实现方法
要实现从树形节点下层向上聚合最小日期,需要调整递归逻辑,从叶子节点开始向上计算,每个父节点的最小日期取自身日期与所有子节点最小日期的最小值。以下是修改后的完整查询:
-- 获取指定树形结构的所有节点(保留原查询的@Top筛选逻辑) WITH cteP AS ( SELECT WBS, WBSParent, StartActual, HierID = CONVERT(hierarchyid, CONCAT('/', WBS, '/')) FROM MSP.MSPMAIN WHERE ISNULL(@Top,-1) = CASE WHEN @Top IS NULL THEN ISNULL(WBSParent, -1) ELSE WBS END UNION ALL SELECT r.WBS, r.WBSParent, r.StartActual, CONVERT(hierarchyid, CONCAT(p.HierID.ToString(), r.WBS, '/')) FROM MSP.MSPMAIN r JOIN cteP p ON r.WBSParent = p.WBS ), -- 标记当前树形中的叶子节点(无下属子节点的节点) cteNodesWithLeaf AS ( SELECT *, IsLeaf = CASE WHEN NOT EXISTS (SELECT 1 FROM cteP c WHERE c.WBSParent = p.WBS) THEN 1 ELSE 0 END FROM cteP p ), -- 从叶子节点向上递归聚合最小日期 cteMinDate AS ( -- 锚点:叶子节点的最小日期为自身的StartActual SELECT WBS, WBSParent, StartActual, HierID, MinStartDate = StartActual FROM cteNodesWithLeaf WHERE IsLeaf = 1 UNION ALL -- 递归:父节点计算自身与子节点的最小日期 SELECT p.WBS, p.WBSParent, p.StartActual, p.HierID, MinStartDate = CASE WHEN p.StartActual IS NOT NULL THEN MIN(p.StartActual, c.MinStartDate) ELSE c.MinStartDate END FROM cteNodesWithLeaf p JOIN cteMinDate c ON p.WBS = c.WBSParent WHERE NOT EXISTS (SELECT 1 FROM cteMinDate c2 WHERE c2.WBS = p.WBS) ) -- 最终输出结果,按层级排序 SELECT Lvl = HierID.GetLevel(), WBS, WBSParent, StartActual, MinStartDate FROM cteMinDate ORDER BY HierID;
逻辑说明
- 节点筛选与层级构建:
cteP保留原查询的逻辑,获取指定@Top节点下的所有树形节点及层级信息。 - 叶子节点标记:
cteNodesWithLeaf识别当前树形中的叶子节点(无下属子节点),作为聚合的起点。 - 从下到上聚合:
cteMinDate递归计算:- 叶子节点的最小日期直接取自身的
StartActual。 - 父节点的最小日期取自身
StartActual(若不为空)与所有子节点MinStartDate的最小值;若自身日期为空,则直接继承子节点的最小日期。
- 叶子节点的最小日期直接取自身的
示例数据验证
针对你提供的示例数据,查询会输出:
- 节点
225117的MinStartDate为2022-10-23,其所有父节点(22511、2251)的MinStartDate也会继承这个值。 - 节点
225216的MinStartDate为2022-08-01,其所有父节点(22521、2252、225)的MinStartDate会取这个最小日期。
内容的提问来源于stack exchange,提问作者Miad BayaniRad
相关产品推荐
相关产品推荐

