coalesce(lag()) 仅用于兜底首行null,不能补真实缺失数据;补时间点需先生成序列再left join,插值需前后非null值支撑,且coalesce应置于select层而非join或where中。

COALESCE(LAG()) 是填首行 NULL 的标准解法,不是补数据缺失
LAG() 对第一行返回 NULL 是函数行为边界,不是原始数据缺值。直接用 COALESCE(LAG(col) OVER (ORDER BY ts), default_val) 是最常用、最安全的首行兜底方式。它不改变序列逻辑,只让后续计算(比如差值、变化率)不中断。
常见错误现象:value - LAG(value) 在首行得到 NULL,导致整列结果变 NULL;或除以 LAG(value) 时触发 division by zero 错误。
- 必须显式写
COALESCE(LAG(value) OVER (ORDER BY ts), value)—— 用当前行值填充,语义最合理 - 不能写
COALESCE(LAG(value), 0):0 可能破坏量纲(如温度从 -5 跳到 0 不是“无变化”) - ORDER BY 必须用真实时间戳字段(如
ts),不能用自增id,否则物理顺序错乱 - 若
ts有重复,需加ROW_NUMBER() OVER (PARTITION BY ts ORDER BY id)辅助去重排序
真正补缺失时间点,得先生成日期序列再 LEFT JOIN
COALESCE 和 LAG 都无法凭空造出数据库里根本不存在的时间点。要补“某天没记录”这种业务缺失,必须用 generate_series()(PostgreSQL)或递归 CTE(MySQL 8.0+/SQL Server)先生成完整时间轴,再左连接原始表。
典型错误是把 COALESCE(LAG(), ...) 当成万能补全工具,结果发现 2023-01-15 这天整条记录都没进库,LAG 也拿不到前值,更没法靠 COALESCE 拉回来。
- PostgreSQL 示例:
generate_series('2023-01-01'::DATE, '2023-01-31'::DATE, '1 day') - 关联时注意对齐粒度:原始表用
DATE(ts),生成序列用::DATE,类型一致才匹配 - LEFT JOIN 后,原始字段为
NULL,此时再用COALESCE(SUM(amount), 0)填聚合值 - WHERE 条件(如
status = 'active')必须挪到 JOIN 的ON子句里,否则变相转成 INNER JOIN
LAG + COALESCE 做线性插值,需要前后非 NULL 值支撑
如果缺失的是中间某几个点(比如传感器每 10 秒采样,但某次网络抖动丢了 3 条),可以用 LAG 找前值、LEAD 找后值,再结合 COALESCE 做线性插值。但这要求前后至少各有一个真实非 NULL 值。
错误做法:对连续多个 NULL 使用 COALESCE(LAG(val), LEAD(val)) —— 它只会取第一个非 NULL,不是插值,而是“就近拷贝”,会放大阶梯误差。
- 正确结构是子查询先拿到
prev_val、prev_ts、next_val、next_ts,再在外部用(next_val - prev_val) * (ts - prev_ts) / NULLIF(next_ts - prev_ts, 0) + prev_val - 时间字段必须转成可计算单位(如
EXTRACT(EPOCH FROM ts)),不能直接减两个TIMESTAMP - 插值结果建议显式
::NUMERIC(10,3)控制精度,避免浮点误差累积 - 空值太多时(如连续 >5 行 NULL),插值已无物理意义,应标记为
'interpolated_unreliable'而非硬算
COALESCE 放错位置会导致 JOIN 语义崩塌
在 ON 条件里写 COALESCE(a.ts, '1970-01-01') = COALESCE(b.ts, '1970-01-01') 看似“让空时间也能连”,实则把两条本不该关联的记录强行绑在一起,且彻底破坏索引。
真正该用 COALESCE 的地方,永远是 SELECT 列表里对已 JOIN 完成的结果做展示层兜底。
- LEFT JOIN 后,右表字段天然为
NULL,这时COALESCE(t2.value, t1.fallback, -1)才是合理链式取值 - 多源字段合并前,必须确认语义一致(都是“用户主电话”)、优先级明确(公司号 > 个人号 > 默认号)、类型兼容(都转成
VARCHAR(20)) - 空字符串
''不等于NULL,要先NULLIF(TRIM(val), '')再进 COALESCE - WHERE 中出现
COALESCE(ts, '1970-01-01') > '2023-01-01'会让ts列完全无法走索引
实际补时间序列,核心就两件事:先用生成序列 + LEFT JOIN 把“空档期”拉出来,再用 COALESCE 在 SELECT 层安全兜底。LAG 是辅助定位上下文的工具,不是补数据的引擎。最容易被忽略的是——你得先想清楚“哪些时间点本该有数据”,这个元信息不在 SQL 里,而在业务规则里。











