如何通过循环结合LAG函数更新数据表,填充SeriesNumber列零值?
别担心,这个需求一点都不难——你完全不需要写循环,只是没找对更高效的实现方式而已!你要做的其实是向前填充(Forward Fill):把SeriesNumber列中值为0的行,替换成最近的上方非0值。
推荐方案:用窗口函数实现(高效且简洁)
现在几乎所有现代数据库都支持窗口函数,这是处理这类填充需求的最优解,性能比循环好太多。下面给几个主流数据库的实现代码:
SQL Server
WITH NumberGroups AS ( SELECT RowNumber, SeriesNumber, -- 给每个连续的非0值分组,0会继承前一个非0组的ID SUM(CASE WHEN SeriesNumber != 0 THEN 1 ELSE 0 END) OVER (ORDER BY (SELECT NULL)) AS GroupId FROM YourTableName ) UPDATE NumberGroups SET SeriesNumber = MAX(SeriesNumber) OVER (PARTITION BY GroupId) WHERE SeriesNumber = 0;
MySQL 8.0+
WITH NumberGroups AS ( SELECT RowNumber, SeriesNumber, SUM(CASE WHEN SeriesNumber != 0 THEN 1 ELSE 0 END) OVER (ORDER BY RowNumber) AS GroupId FROM YourTableName ) UPDATE YourTableName t JOIN NumberGroups ng ON t.RowNumber = ng.RowNumber SET t.SeriesNumber = (SELECT MAX(SeriesNumber) FROM NumberGroups WHERE GroupId = ng.GroupId) WHERE t.SeriesNumber = 0;
PostgreSQL
WITH NumberGroups AS ( SELECT RowNumber, SeriesNumber, SUM(CASE WHEN SeriesNumber != 0 THEN 1 ELSE 0 END) OVER (ORDER BY RowNumber) AS GroupId FROM YourTableName ) UPDATE YourTableName t SET SeriesNumber = fill_values.fill_value FROM ( SELECT GroupId, MAX(SeriesNumber) AS fill_value FROM NumberGroups GROUP BY GroupId ) fill_values JOIN NumberGroups ng ON ng.GroupId = fill_values.GroupId WHERE t.RowNumber = ng.RowNumber AND t.SeriesNumber = 0;
为什么不用循环?
循环处理数据表的效率极低,尤其是数据量较大时,数据库需要逐行操作,性能开销很大。而窗口函数是数据库原生优化过的批量操作,不仅代码简洁,执行速度也快得多。你之前觉得需要循环,只是因为没接触过这种向前填充的窗口函数实现思路,完全不是需求难度高的问题~
执行后效果
运行完上述代码,你的表就会变成你期望的状态:
RowNumber SeriesNumber
1 1
2 1
3 1
4 1
1 2
2 2
1 3
2 3
1 4
内容的提问来源于stack exchange,提问作者Incompetent77
相关产品推荐
相关产品推荐

