在数据分析与业务报表开发中,源数据经常出现缺失值,尤其是按时间或类别分区的指标字段。如果只用普通的聚合或单行函数,往往要么丢掉整行,要么被迫填零,结果都不够真实。把SQL窗口函数和COALESCE结合起来,可以在不破坏原有行数的前提下,用相邻或同组的有效数据来填补空缺,从而让累计、排名、移动平均等计算保持连贯。

一、为什么单用COALESCE不够
COALESCE函数本身只做一件事:从左往右返回第一个非空表达式。比如COALESCE(score, 0)会把空成绩变成零。但在按用户、按天排序的场景里,零和“没有发生”是完全不同的概念。填零会让后续求和、平均被无意义地拉低,而业务上更希望用“上一次已知的值”或“同组平均值”来近似。
这时候如果写自连接去取前一条记录,SQL会非常冗长,而且分区、排序条件一多就容易出错。窗口函数恰好能在一个SELECT里定义“如何划窗、如何排序”,再交给COALESCE决定最终落什么值,两者职责清晰、性能也好。
二、用LAG加COALESCE向前填充
最常见的缺失值处理是“向前补齐”:同一用户的最新缺失指标,沿用该用户之前最近一次的非空值。下面用一张用户积分表举例,部分日期没有签到因而积分为NULL。
SELECT
user_id,
record_date,
raw_score,
COALESCE(
raw_score,
LAG(raw_score) IGNORE NULLS OVER (
PARTITION BY user_id ORDER BY record_date
)
) AS filled_score
FROM user_score_log;
上面代码中,LAG(raw_score) IGNORE NULLS表示在用户分区内按日期排序,跳过空值取前一条有效积分。如果当天raw_score是NULL,COALESCE就会用LAG拿到的值补上;若前面也没有,结果仍为NULL,可后续再处理。
并非所有数据库都支持IGNORE NULLS语法。在MySQL等不支持的库里,可以借助子查询或两次窗口函数实现:先取最大非空日期对应的分值,再交给COALESCE。核心思想不变,只是写法稍绕。
三、用AVG窗口函数补缺失日活
除了向前补,有时更适合用“同组平均”来填缺失,比如每日活跃用户数漏采时,用该周其余天的均值近似。COALESCE在这里负责判断是否需要兜底。
SELECT
dt,
region,
dau,
COALESCE(
dau,
AVG(dau) OVER (
PARTITION BY region
ORDER BY dt
ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING
)
) AS dau_filled
FROM region_dau_stats;
这段语句在region分区内,以当天为中心取前后各三天的窗口求平均。若dau为NULL,COALESCE用该均值替换,既平滑了曲线,也避免了自连接带来的重复扫描。
要注意的是,窗口平均本身也会忽略NULL(多数数据库AVG忽略空值),因此不会因为空缺而算错分母。如果希望把补过的值再参与后面计算,可以把上面查询作为子查询,外层继续用窗口函数做累计。
四、SUM累计场景下的配合技巧
做累计求和时,缺失值若不处理,运行总和会出现“断档”。结合COALESCE与窗口函数,可以先补齐再求和,保证折线连续。
WITH filled AS (
SELECT
user_id,
trade_date,
COALESCE(
amount,
LAG(amount) IGNORE NULLS OVER (
PARTITION BY user_id ORDER BY trade_date
)
) AS amount_filled
FROM user_trade
)
SELECT
user_id,
trade_date,
SUM(amount_filled) OVER (
PARTITION BY user_id ORDER BY trade_date
) AS running_sum
FROM filled;
这里先用CTE把补齐逻辑独立出来,再在外层用SUM开窗做累计。这样代码可读性高,也方便单独测试补齐效果。如果某些用户第一条就是NULL,LAG取不到值,可在COALESCE里再加一层默认值,例如COALESCE(..., 0)。
从执行计划看,窗口函数通常只需对数据排序一次,比多层自连接少很多随机IO。在千万级日志表上,这种写法往往能省下几倍耗时。
五、易混淆点与使用建议
有人会把<input>这类前端标签和SQL函数搞混,但在数据库里我们说的就是COALESCE函数,不是任何HTML元素。另外,窗口函数中的ORDER BY只影响窗内顺序,不改变最终输出行的物理顺序,若需要最终结果按某列排,外层还要再写ORDER BY。
实际落地时,建议先确认业务对缺失的容忍方式:向前补适合状态类指标,平均补适合流量类指标,填零仅用于确实代表“无”的计数。配合COALESCE,只需替换被包裹的表达式,主体窗口逻辑可以稳定复用。
| 缺失处理方式 | 适用指标 | 典型窗口函数 |
|---|---|---|
| 向前补齐 | 积分、等级、余额 | LAG / FIRST_VALUE |
| 邻近平均 | 日活、响应时长 | AVG with ROWS |
| 分组常量 | 地区均价、类目基准 | MAX / MIN OVER |
把窗口函数和COALESCE组合进日常ETL或即席查询,既能让SQL保持简洁,也能输出更贴近业务真相的结果。下次遇到NULL满天飞的分区报表,不妨先想清楚补齐策略,再用上面几种模式改写。