在SQL查询中,窗口函数可以对分组内的行做聚合或排序而不折叠行。如果希望聚合时只计入符合特定条件的记录,可以把CASE WHEN表达式放在窗口函数的聚合参数里,通过条件返回原值或NULL来控制计算范围。

什么是带条件的窗口聚合
普通窗口聚合会对分区内所有行计算,例如SUM(amount) OVER(PARTITION BY dept)会求和部门全部金额。带条件的窗口聚合只在满足CASE WHEN条件时才把数值纳入计算,其余返回NULL或0,从而实现筛选式统计。
基础语法结构
核心写法是将CASE WHEN作为聚合函数的输入:
SELECT
dept,
emp_name,
amount,
-- 只累计金额大于1000的记录
SUM(CASE WHEN amount > 1000 THEN amount ELSE 0 END)
OVER(PARTITION BY dept ORDER BY sale_date) AS cond_running_sum
FROM sales;
上面代码中,CASE WHEN判断amount是否大于1000,满足才返回amount,否则返回0,再交给SUM窗口函数做有序累计。
常见使用场景
- 统计每个用户截止当前日期的有效订单总额,无效订单不计入
- 计算部门内高绩效员工的滚动平均,排除低绩效记录
- 按条件标记累计次数,例如仅统计退款成功的笔数
完整示例
假设有销售表sales,字段为dept、emp_name、sale_date、amount,需求是查询每人所在部门中,业绩大于800的滚动总和:
SELECT
dept,
emp_name,
sale_date,
amount,
SUM(CASE
WHEN amount > 800 THEN amount
ELSE 0
END)
OVER(
PARTITION BY dept
ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS high_amount_cum
FROM sales
ORDER BY dept, sale_date;
该查询按部门分区、销售日期排序,使用ROWS框架明确累计范围,CASE WHEN确保只加总大于800的金额。
注意事项
NULL与0的区别
聚合函数如SUM会忽略NULL,因此写ELSE NULL与ELSE 0在SUM中效果类似;但AVG中若写0会拉低均值,此时应用NULL排除。
执行顺序
窗口函数在WHERE之后执行,因此CASE WHEN里不能使用聚合别名,只能引用原表列或外层子查询提供的列。
数据库兼容
MySQL 8.0、PostgreSQL、SQL Server均支持该写法。低版本MySQL若无窗口函数,需用变量模拟,不推荐。
小结
把CASE WHEN嵌套进窗口聚合函数,是实现带条件统计的简洁方案。掌握条件返回值的选择与窗口框架定义,就能灵活应对各类报表计算。