SQL Server替换NULL值:非循环实现填充最近非空数值
不用WHILE循环填充NULL为最近上一个非空值的T-SQL实现
这是个非常典型的缺失值填充需求,完全不需要用效率较低的WHILE循环,我们可以借助窗口函数来高效实现,下面提供两种适配不同SQL Server版本的方案:
兼容所有SQL Server版本的通用方案
这个方法通过生成分组ID,把连续的NULL和它前面的非空值归为一组,再取组内的非空值来填充:
DECLARE @TABLE TABLE( id int primary key identity(1,1), code int ); INSERT INTO @TABLE VALUES (1),(NULL),(NULL),(NULL),(2),(NULL),(NULL),(NULL),(3),(NULL),(NULL),(NULL); SELECT id, MAX(code) OVER (PARTITION BY group_id) AS filled_code FROM ( SELECT id, code, -- 核心逻辑:每遇到非空code就递增分组ID,将连续NULL归到上一个非空值的组 SUM(CASE WHEN code IS NOT NULL THEN 1 ELSE 0 END) OVER (ORDER BY id) AS group_id FROM @TABLE ) AS subquery;
原理说明
- 内层子查询中,
SUM(CASE WHEN code IS NOT NULL THEN 1 ELSE 0 END) OVER (ORDER BY id)会生成一个递增的分组ID:- 当遇到非空的
code时,分组ID加1; - 后续的NULL行都会继承这个分组ID,直到下一个非空值出现。
- 当遇到非空的
- 外层查询通过
MAX(code) OVER (PARTITION BY group_id),每个分组里只有一个非空的code值,所以MAX函数会直接取到这个值,填充所有同组的NULL位置。
SQL Server 2022及以上的简化方案
如果你的SQL Server版本是2022或更新,官方支持了IGNORE NULLS参数,可以直接用LAST_VALUE函数一步到位:
DECLARE @TABLE TABLE( id int primary key identity(1,1), code int ); INSERT INTO @TABLE VALUES (1),(NULL),(NULL),(NULL),(2),(NULL),(NULL),(NULL),(3),(NULL),(NULL),(NULL); SELECT id, LAST_VALUE(code) OVER ( ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW IGNORE NULLS ) AS filled_code FROM @TABLE;
原理说明
LAST_VALUE(code) OVER (...) IGNORE NULLS会在当前行及之前的所有行中,忽略NULL值,直接取最近的那个非空code值,完美匹配你的需求。
内容的提问来源于stack exchange,提问作者EmreB.
相关产品推荐
相关产品推荐

