窗口函数不支持where过滤,条件累加必须用case when嵌套在sum() over()内并显式写else 0;多维度聚合需先group by再开窗;多条件判断要严格按逻辑优先级嵌套case when,并处理null值。

直接用 SUM() OVER() 加 WHERE 不行——窗口函数不接受 WHERE 过滤,条件必须在窗口外或用 CASE WHEN 内嵌处理。
条件累加必须用 CASE WHEN 嵌套在 SUM() OVER() 里
想“只累加金额 > 100 的订单”,不能先 WHERE amount > 100 再窗口累加,否则会丢掉组内其他行(比如同一用户的低金额订单仍需保留,只是不参与累加)。正确做法是把条件逻辑塞进窗口函数内部:
SUM(CASE WHEN amount > 100 THEN amount ELSE 0 END) OVER (PARTITION BY user_id ORDER BY order_time)- 别写成
SUM(IF(amount > 100, amount, 0))——IF是 MySQL 特有,跨数据库兼容性差;CASE WHEN是 SQL 标准,PostgreSQL、SQL Server、Oracle 都认 - 返回
NULL而不是0会导致累加中断(比如100 + NULL = NULL),所以ELSE 0必须显式写上
GROUP BY 后再窗口累加?先聚合再开窗才安全
如果原始数据粒度太细(比如每笔订单),但你想按“用户+月份”分组后再算累计,就不能直接对明细行开窗。否则会重复累加同月多笔订单,结果虚高。必须先聚合,再对聚合结果开窗:
- 子查询里用
GROUP BY user_id, YEAR(order_date), MONTH(order_date)算出每月总金额 - 外层查用
SUM(monthly_total) OVER (PARTITION BY user_id ORDER BY year, month) - 注意:子查询的
ORDER BY字段(如year, month)必须和窗口函数里的PARTITION BY/ORDER BY字段类型一致——别把YEAR(order_date)当字符串拼接,MySQL 会当成字符排序,2025可能排在202412前面
多个条件叠加时,CASE WHEN 的嵌套顺序影响结果
业务常要求“只累加已发货且未退款的订单”。这时 CASE WHEN 的判断链要严格按逻辑优先级写,漏掉 ELSE 0 或顺序颠倒都会出错:
- 错误写法:
CASE WHEN status = 'shipped' THEN amount WHEN refund_flag = 0 THEN amount ELSE 0 END→ 满足第一个条件就跳过后续判断,退款单可能被误加 - 正确写法:
CASE WHEN status = 'shipped' AND refund_flag = 0 THEN amount ELSE 0 END - 更稳妥的写法是拆成布尔表达式:
CASE WHEN status = 'shipped' AND COALESCE(refund_flag, 1) = 0 THEN amount ELSE 0 END,显式处理refund_flag为NULL的情况
最易被忽略的是:条件累加的结果列,和原始行的业务含义必须对齐。比如你按用户开窗累加,但某行记录的 order_time 是 NULL,它会被排在组最前或最后,导致整组累计值错位——别依赖数据库默认 NULL 排序行为,用 COALESCE(order_time, '1970-01-01') 显式控制。











