当前位置: 首页 > news >正文

SQL Server 进阶:递归 CTE+CASE WHEN 实现复杂树形统计(第二课)

在《SQL Server 函数实战:一条 SQL 替代 3000 行代码的计算逻辑》基础上,我们进一步拓展业务需求,实现更复杂的层级数据统计。本次将重点解决两个核心问题:一是统计每个部门(含所有下级部门)请假天数大于 3 天的记录数量;二是让上级部门的统计结果自动汇总所有下级部门数据,实现树形结构的递归统计。通过递归 CTE、CASE WHEN函数与分组聚合的深度结合,完成从基础数据统计到层级化数据分析的跨越。

一、业务需求升级:层级汇总与新增统计维度

核心目标

  1. 递归汇总:上级部门的数据需包含直属及非直属下级部门的所有数据,例如集团总部要汇总技术研发部、产品运营部及其子部门的全部请假数据。
  2. 新增统计项:统计每个部门(含各级上级部门)请假天数大于 3 天的记录数量。
  3. 兼容原有指标:保留原有请假类型天数统计、请假状态分类统计等功能。

数据模型扩展(无需修改表结构,新增计算逻辑)

-- 新增判断逻辑:标记请假天数>3天的记录CASE WHEN leave_days > 3 THEN 1 ELSE 0 END AS over_3_days_flag

二、关键技术升级:双向递归 CTE 构建层级关系

1. 递归 CTE 重构:获取每个部门的所有后代部门

WITH dept_ancestor AS (-- 初始层:每个部门自身作为祖先SELECTdept_id,dept_name,parent_dept_id,dept_id AS ancestor_id -- 核心字段:标记当前部门的顶层祖先FROM t_deptUNION ALL-- 递归层:向下遍历子部门,继承祖先IDSELECTd.dept_id,d.dept_name,d.parent_dept_id,da.ancestor_id -- 子部门继承父部门的祖先IDFROM t_dept dJOIN dept_ancestor da ON d.parent_dept_id = da.dept_id)
  • 核心逻辑:为每个部门生成从自身到所有后代的层级路径,ancestor_id表示当前统计的顶层部门(如子部门 4 的ancestor_id可为自身 4、父部门 2、根部门 1)。
  • 递归方向:从父部门到子部门的向下递归,确保每个子部门关联到所有上级祖先。

2. 关联请假表与递归 CTE

 

三、CASE WHEN 函数进阶:多维度条件聚合

1. 新增 "请假 > 3 天" 统计


SELECTda.ancestor_id, -- 统计的目标部门(上级部门)da_dept.dept_name, -- 目标部门名称tl.dept_id AS child_dept_id -- 实际产生数据的子部门ID(用于验证层级)FROM dept_ancestor daLEFT JOIN t_dept da_dept ON da.ancestor_id = da_dept.dept_id -- 关联祖先部门信息LEFT JOIN t_leave tl ON da.dept_id = tl.dept_id -- 关联子部门请假数据-- 示例输出:祖先部门1(集团总部)会关联到子部门2、3、4、5的所有请假记录
SUM(CASE WHEN tl.leave_days > 3 THEN 1 ELSE 0 END) AS over_3_days_count

此语句通过CASE WHEN判断请假天数是否大于 3 天,若满足条件则计数为 1,否则为 0,最后使用SUM函数汇总,实现对请假天数大于 3 天记录数量的统计。

2. 全维度统计表达式(整合新旧需求)

SELECTda_dept.dept_name AS 部门名称,-- 请假类型统计(含下级部门)SUM(CASE tl.leave_type WHEN '年假' THEN tl.leave_days ELSE 0 END) AS 年假总天数,SUM(CASE tl.leave_type WHEN '事假' THEN tl.leave_days ELSE 0 END) AS 事假总天数,SUM(CASE tl.leave_type WHEN '病假' THEN tl.leave_days ELSE 0 END) AS 病假总天数,-- 状态统计SUM(CASE tl.leave_status WHEN '完成' THEN 1 ELSE 0 END) AS 完成请假数,SUM(CASE tl.leave_status WHEN '进行中' THEN 1 ELSE 0 END) AS 进行中请假数,-- 新增统计:请假>3天SUM(CASE WHEN tl.leave_days > 3 THEN 1 ELSE 0 END) AS 超3天请假数

四、终极 SQL:递归汇总全层级数据

完整实现代码

WITH dept_ancestor AS (-- 构建部门层级关系,获取每个部门的所有祖先路径SELECTdept_id,dept_name,parent_dept_id,dept_id AS ancestor_id -- 初始祖先为自身FROM t_deptUNION ALL-- 递归向下遍历子部门,继承祖先IDSELECTd.dept_id,d.dept_name,d.parent_dept_id,da.ancestor_id -- 子部门的祖先与父部门一致FROM t_dept dJOIN dept_ancestor da ON d.parent_dept_id = da.dept_id),-- 提取祖先部门的基础信息(避免重复计算)ancestor_info AS (SELECT DISTINCT ancestor_id, dept_nameFROM dept_ancestor)SELECTai.dept_name AS 部门名称,-- 请假类型汇总(含所有子部门)SUM(CASE tl.leave_type WHEN '年假' THEN tl.leave_days ELSE 0 END) AS 年假总天数,SUM(CASE tl.leave_type WHEN '事假' THEN tl.leave_days ELSE 0 END) AS 事假总天数,SUM(CASE tl.leave_type WHEN '病假' THEN tl.leave_days ELSE 0 END) AS 病假总天数,-- 状态汇总SUM(CASE tl.leave_status WHEN '完成' THEN 1 ELSE 0 END) AS 完成请假数,SUM(CASE tl.leave_status WHEN '进行中' THEN 1 ELSE 0 END) AS 进行中请假数,-- 新增统计项SUM(CASE WHEN tl.leave_days > 3 THEN 1 ELSE 0 END) AS 超3天请假数FROM ancestor_info aiLEFT JOIN dept_ancestor da ON ai.ancestor_id = da.ancestor_idLEFT JOIN t_leave tl ON da.dept_id = tl.dept_id -- 关联子部门请假数据GROUP BY ai.ancestor_id, ai.dept_nameORDER BY ai.ancestor_id;

执行结果解析(新增示例数据后)

部门名称

年假总天数

事假总天数

病假总天数

完成请假数

进行中请假数

超 3 天请假数

集团总部

8.5

2.0

3.0

2

3

2

技术研发部

4.5

2.0

0.0

1

2

2

产品运营部

1.5

0.0

3.0

1

1

0

后端开发组

3.5

0.0

0.0

1

1

1

前端开发组

0.0

2.0

0.0

0

1

1

核心逻辑拆解

1、递归 CTE 双向关联

        向上:每个部门作为祖先,向下遍历所有子部门(ancestor_id固定为顶层部门)。

        向下:通过da.dept_id = tl.dept_id关联子部门的实际数据,确保上级部门能获取所有下级数据。

2、CASE WHEN 的多维应用

        类型统计:按leave_type分类累加天数。

        状态统计:按leave_status分类计数。

        数值判断:通过CASE WHEN直接判断天数是否大于 3,简化条件转换。

 3、分组策略

        按ancestor_id分组,确保每个上级部门汇总其所有后代(包括多级子部门)的数据。

        LEFT JOIN确保无数据部门(如根部门若自身无数据)仍能显示统计结果。

五、与第一课的核心区别

特性

第一课(单部门统计)

本文(递归层级统计)

统计范围

仅当前部门或指定子部门

包含所有下级部门(多级递归)

递归方向

单向向下(固定根部门)

双向关联(每个部门可作为祖先)

核心字段

dept_id直接分组

ancestor_id递归分组

新增功能

请假天数 > 3 天统计、层级汇总

六、性能优化与注意事项

1. 索引优化建议

-- 为部门层级关系创建索引CREATE INDEX idx_dept_parent ON t_dept(parent_dept_id);-- 为请假表关联字段创建索引CREATE INDEX idx_leave_dept ON t_leave(dept_id);

2. 大数据量处理

在 SQL Server 中,递归 CTE 默认有 100 层的递归限制,若部门层级较深,可通过以下方式调整:

-- 设置最大递归层数为200OPTION (MAXRECURSION 200);

3. CASE WHEN vs IIF 函数

  • CASE WHEN支持复杂的条件判断和多分支逻辑,适用于大多数场景。
  • IIF函数是CASE WHEN的简化写法,仅支持简单的二选一判断(如IIF(leave_days > 3, 1, 0)),在复杂逻辑中不适用。

七、总结:树形数据统计的进阶解决方案

通过递归 CTE 构建层级关系、CASE WHEN实现条件聚合、分组函数完成数据汇总,我们在 SQL Server 中实现了真正的层级递归统计。这种方案不仅能处理复杂的组织架构数据,还能灵活扩展统计维度,相比传统编程方式大幅减少代码量,提升开发效率与数据处理性能。后续我们还将继续探索更高级的统计分析功能,如果你有其他想实现的业务逻辑或优化需求,欢迎随时交流探讨。

http://www.dtcms.com/a/263679.html

相关文章:

  • 【Python基础】12 闲谈分享:Python用于无人驾驶的未来
  • 借助飞算AI新手小白快速入门Java实操记录
  • 嵌入式编程-使用AI查找BUG的启发
  • AG32调试bug集合
  • [论文阅读] 人工智能 + 软件工程 | 从软件工程视角看大语言模型:挑战与未来之路
  • 基于 Vue + RuoYi 架构设计的商城Web/小程序实训课程
  • 企业级应用技术-ELK日志分析系统
  • java生成word文档
  • 11年考研作文真题大数据
  • 边缘人工智能与医疗AI融合发展路径:技术融合与应用前景(下)
  • SpringBoot计时一次请求耗时
  • mac python3.13 selenium安装使用
  • [特殊字符] 分享裂变新姿势:用 UniApp + Vue3 玩转小程序页面分享跳转!
  • IntelliJ IDEA 2025- 下载安装教程图文版详细教程(附激活码)
  • Python 库 包 nltk (Natural Language Toolkit)
  • 类加载生命周期与内存区域详解
  • 【FR801xH】富芮坤FR801xH之UART
  • npm list的使用方法详细介绍
  • 基于 Three.js 与 WebGL 的商场全景 VR 导航系统源码级解析
  • python 操作 hive
  • vue | 插件 | 移动文件的插件 —— move-file-cli 插件 的安装与使用
  • RabbitMQ - SpringAMQP及Work模型
  • C++仿函数与谓词深度解析:函数对象的艺术
  • android apk签名
  • 文件系统之配置网络参数
  • SiFli 52 UART的RX唤醒MCU怎么做
  • 飞算 JavaAI:我的编程强力助推引擎
  • Vue Vue-route (3)
  • Web性能测试常用指标(转自百度AI)
  • PHP爬虫实战指南:获取淘宝商品详情