如何用前一个非空值填充数据表中的空值行?
高效填充MyValue列空值为前一个非空值的方案
原始数据表
ID|Month|MyValue 1|202212|null 1|202211|bbb 1|202210|null 1|202209|null 1|202208|aaa
目标结果
ID|Month|MyValue 1|202212|bbb 1|202211|bbb 1|202210|aaa 1|202209|aaa 1|202208|aaa
核心思路
按ID分组,按Month降序排序(确保时间靠后的行优先获取最近的非空值),利用窗口函数向前填充非空值,这种方式避免了游标或循环,效率远高于逐行处理。
各数据库实现方案
MySQL 8.0+ / PostgreSQL / SQL Server
支持IGNORE NULLS版本(MySQL 8.0.22+、PostgreSQL、SQL Server)
使用LAST_VALUE窗口函数直接跳过空值,取当前行及之前的最后一个非空值:
SELECT ID, Month, LAST_VALUE(MyValue IGNORE NULLS) OVER ( PARTITION BY ID ORDER BY Month DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS MyValue FROM your_table;
MySQL 8.0.22之前版本
由于不支持IGNORE NULLS,可以用MAX()窗口函数替代(非空值会覆盖空值的最大值):
SELECT ID, Month, MAX(MyValue) OVER ( PARTITION BY ID ORDER BY Month DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS MyValue FROM your_table;
Oracle
Oracle原生支持LAST_VALUE加IGNORE NULLS,语法更简洁:
SELECT ID, Month, LAST_VALUE(MyValue IGNORE NULLS) OVER ( PARTITION BY ID ORDER BY Month DESC ROWS UNBOUNDED PRECEDING ) AS MyValue FROM your_table;
更新原表的方案(以MySQL为例)
如果需要直接更新原表而非仅查询结果,可通过CTE关联更新:
WITH filled_data AS ( SELECT ID, Month, MAX(MyValue) OVER ( PARTITION BY ID ORDER BY Month DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS filled_value FROM your_table ) UPDATE your_table t JOIN filled_data fd ON t.ID = fd.ID AND t.Month = fd.Month SET t.MyValue = fd.filled_value WHERE t.MyValue IS NULL;
内容的提问来源于stack exchange,提问作者Brian Jones
相关产品推荐
相关产品推荐

