如何在SQL中循环对比当前行与前一行值,并实现填充最近True标记对应ID列?
实现最近Flag为True行的ID向前填充
这个需求本质是向前填充最近的有效标识行ID(也就是常说的「last value carry forward」场景),针对主流SQL数据库,我整理了几种可行的实现方案,你可以根据自己使用的数据库选择对应的代码:
1. PostgreSQL 实现
PostgreSQL 11及以上版本支持LAST_VALUE结合IGNORE NULLS,可以直接定位最近的非空值;如果是旧版本,用MAX()窗口函数也能达到效果:
方案一(PostgreSQL 11+)
SELECT A, B, LAST_VALUE(CASE WHEN B THEN A END) OVER ( ORDER BY A ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW IGNORE NULLS ) AS C FROM your_table;
方案二(兼容所有PostgreSQL版本)
利用MAX()函数自动忽略NULL的特性,窗口范围限定为从起始行到当前行,就能得到最近的Flag为True的ID:
SELECT A, B, MAX(CASE WHEN B THEN A END) OVER ( ORDER BY A ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS C FROM your_table;
2. MySQL 实现
MySQL 8.0及以上支持窗口函数,写法和PostgreSQL类似;如果是5.x版本,需要用自定义变量来实现:
方案一(MySQL 8.0+)
SELECT A, B, LAST_VALUE(CASE WHEN B = 'T' THEN A END) OVER ( ORDER BY A ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS C FROM your_table;
方案二(MySQL 5.x)
通过初始化变量来记录最近的Flag为True的ID,遍历行时动态更新变量值:
SELECT A, B, @current_true_id := CASE WHEN B = 'T' THEN A ELSE @current_true_id END AS C FROM your_table, (SELECT @current_true_id := NULL) AS init_var ORDER BY A;
注意:必须保证
ORDER BY A的存在,因为要按照ID的顺序遍历行,才能正确继承最近的有效ID。
3. SQL Server 实现
SQL Server 2012及以上支持窗口函数,两种写法都能实现需求:
方案一(LAST_VALUE)
SELECT A, B, LAST_VALUE(CASE WHEN B = 'T' THEN A END) OVER ( ORDER BY A ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS C FROM your_table;
方案二(MAX窗口函数)
SELECT A, B, MAX(CASE WHEN B = 'T' THEN A END) OVER ( ORDER BY A ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS C FROM your_table;
验证结果
用你提供的示例数据测试以上代码,都会得到预期的输出:
A B C
1 T 1
2 F 1
3 F 1
4 T 4
5 T 5
6 F 5
7 T 7
8 F 7
9 F 7
10 F 7
11 T 11
内容的提问来源于stack exchange,提问作者user_mf_cloud
相关产品推荐
相关产品推荐

