在企业级应用开发过程中,面对复杂的业务统计需求,通常需要编写大量代码来处理数据。前面几篇文章讲述了在Oracle中如何高效利用SQL语句,而在 SQL Server 中,借助CASE WHEN(类似于 Oracle 的DECODE)函数与分组函数的巧妙配合,我们也能够仅用一条 SQL 语句,实现原本需要 3000 行代码才能完成的复杂计算逻辑。本文将围绕企业组织架构中的部门级请假数据统计场景展开,详细介绍SQLserver的具体实现方法。
一、基础准备:构建业务数据表
1. 创建单位部门表(模拟组织架构)
CREATE TABLE t_dept (
dept_id INT PRIMARY KEY, -- 部门ID(主键)
dept_name VARCHAR(50) NOT NULL, -- 部门名称
parent_dept_id INT, -- 上级部门ID(根部门为0)
create_time DATETIME DEFAULT GETDATE() -- 创建时间
);
-- 插入示例数据(三级部门架构)
INSERT INTO t_dept (dept_id, dept_name, parent_dept_id) VALUES (1, '集团总部', 0);
INSERT INTO t_dept (dept_id, dept_name, parent_dept_id) VALUES (2, '技术研发部', 1);
INSERT INTO t_dept (dept_id, dept_name, parent_dept_id) VALUES (3, '产品运营部', 1);
INSERT INTO t_dept (dept_id, dept_name, parent_dept_id) VALUES (4, '后端开发组', 2);
INSERT INTO t_dept (dept_id, dept_name, parent_dept_id) VALUES (5, '前端开发组', 2);
2. 创建人员请假信息表
CREATE TABLE t_leave (
user_id VARCHAR(20) PRIMARY KEY, -- 人员账号(主键)
user_name VARCHAR(30) NOT NULL, -- 人员姓名
dept_id INT NOT NULL, -- 所属部门ID
leave_days DECIMAL(5,1), -- 请假天数(保留1位小数)
leave_type VARCHAR(20), -- 请假类型(年假/事假/病假等)
leave_status VARCHAR(10), -- 请假状态('完成'/'进行中')
apply_time DATETIME DEFAULT GETDATE() -- 申请时间
);
-- 插入模拟数据(覆盖不同部门/类型/状态)
INSERT INTO t_leave VALUES
('U001', '张三', 4, 3.5, '年假', '完成', '2025-06-01'),
('U002', '李四', 5, 2.0, '事假', '进行中', '2025-06-10'),
('U003', '王五', 3, 1.5, '病假', '完成', '2025-06-15'),
('U004', '赵六', 4, 5.0, '年假', '进行中', '2025-06-20'),
('U005', '周七', 2, 1.0, '事假', '完成', '2025-06-05'),
('U006', '吴八', 3, 3.0, '年假', '进行中', '2025-06-25');
二、CASE WHEN 函数基础用法:实现简单条件转换
1. 基础语法解析
CASE expression
WHEN search1 THEN result1
WHEN search2 THEN result2
...
ELSE default
END
CASE WHEN函数类似于 Oracle 的DECODE函数,也类似于编程语言中的switch-case结构,按照顺序匹配条件。它不仅支持数值型和字符型数据比较,还能处理更复杂的逻辑判断,最后一个ELSE子句为默认值(可选) 。
2. 示例:状态码转换
-- 将状态编码转为中文描述
SELECT
user_name,
leave_type,
CASE leave_status
WHEN '完成' THEN '已完成'
WHEN '进行中' THEN '处理中'
ELSE '未知状态'
END AS status_desc
FROM t_leave;
-- 输出结果:
-- 张三 年假 已完成
-- 李四 事假 处理中
-- 王五 病假 已完成
三、CASE WHEN 进阶用法:多条件分支处理
1. 复杂业务场景:多维度分类统计
需求:统计不同请假类型的占比(按部门维度)
SELECT
dept_id,
SUM(CASE leave_type WHEN '年假' THEN leave_days ELSE 0 END) AS annual_leave_days,
SUM(CASE leave_type WHEN '事假' THEN leave_days ELSE 0 END) AS personal_leave_days,
SUM(CASE leave_type WHEN '病假' THEN leave_days ELSE 0 END) AS sick_leave_days
FROM t_leave
GROUP BY dept_id;
-- 关键逻辑:
-- 针对每个部门,按请假类型累加对应天数
-- 非目标类型自动返回0,避免NULL影响SUM计算
2. 优势体现
CASE WHEN相较于 Oracle 的DECODE函数,支持更灵活的条件判断,不仅可以进行等值比较,还能处理范围判断(如WHEN leave_days > 3 THEN ...),在复杂业务逻辑处理中更具优势。
四、终极实战:单 SQL 实现三级统计需求
业务目标
从根部门(集团总部,dept_id=1)开始,统计每个子部门的:
1.每种请假类型的总天数
2.完成状态的请假单数
3.进行中状态的请假单数
核心 SQL 语句
WITH dept_hierarchy AS (
-- 递归查询获取所有子部门(包含自身)
SELECT dept_id, dept_name, parent_dept_id
FROM t_dept
WHERE dept_id = 1 -- 根部门ID
UNION ALL
SELECT d.dept_id, d.dept_name, d.parent_dept_id
FROM t_dept d
JOIN dept_hierarchy dh ON d.parent_dept_id = dh.dept_id
)
SELECT
dh.dept_name AS 部门名称,
-- 请假类型统计(年假/事假/病假,其他类型自动归为0)
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 进行中请假数
FROM dept_hierarchy dh
LEFT JOIN t_leave tl ON dh.dept_id = tl.dept_id
GROUP BY dh.dept_id, dh.dept_name
ORDER BY dh.dept_id;
执行结果示例
部门名称 |
年假总天数 |
事假总天数 |
病假总天数 |
完成请假数 |
进行中请假数 |
集团总部 |
0.0 |
0.0 |
0.0 |
0 |
0 |
技术研发部 |
4.5 |
1.0 |
0.0 |
1 |
1 |
产品运营部 |
1.5 |
0.0 |
3.0 |
1 |
1 |
后端开发组 |
3.5 |
0.0 |
0.0 |
1 |
1 |
前端开发组 |
0.0 |
2.0 |
0.0 |
0 |
1 |
关键技术点解析
- 递归 CTE(公用表表达式):构建部门层级关系,实现从根部门到所有子部门的遍历,与 Oracle 的递归查询逻辑相似,但语法更简洁直观。
- CASE WHEN 与 SUM 结合:横向扩展统计维度(类型 / 状态)和自动处理 NULL 值(非匹配项返回 0)
- LEFT JOIN 优化:确保无数据部门也能显示(如集团总部本身无请假记录)
五、总结:SQL 编程的降维打击
通过CASE WHEN函数与分组函数的组合,在 SQL Server 中我们同样实现了:
1、代码量锐减:原本需要 Java/Python 编写的多层循环 + 条件判断,浓缩为单条 SQL
2、性能提升:数据库层直接完成复杂计算,减少数据传输开销
3、维护便利:业务逻辑集中在 SQL 层,无需修改应用代码即可调整统计规则
在 SQL Server 的开发过程中,合理运用CASE WHEN和递归 CTE 等特性,能够极大提升开发效率。后续文章中,我们还将进一步探索更复杂的统计逻辑实现,如果你对当前内容有任何疑问,或想补充特定需求,欢迎随时交流。