SQL Server中无需新增列,如何在窗口内获取首个非空值?
在SQL Server窗口中获取第一个非空值(无需新增列)
由于SQL Server的FIRST_VALUE()不支持IGNORE NULLS参数,你可以通过以下几种方式实现需求:
方法1:适用于所有SQL Server版本
利用CASE语句调整排序权重,让非空值排在窗口最前面,再通过FIRST_VALUE()获取第一个值:
SELECT 分区列名, 排序列名, 目标列名, FIRST_VALUE(目标列名) OVER ( PARTITION BY 分区列名 ORDER BY CASE WHEN 目标列名 IS NOT NULL THEN 0 ELSE 1 END, -- 非空值优先排序 排序列名 -- 保持原排序逻辑 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS 第一个非空值 FROM 你的表名;
原理:通过CASE给非空值分配更低的排序优先级,确保它们出现在窗口的最前面,FIRST_VALUE()就能取到第一个非空值,且该值会被应用到整个分区的所有行。
方法2:适用于SQL Server 2022及以上版本
SQL Server 2022开始支持NULLS LAST/NULLS FIRST,可以简化写法:
SELECT 分区列名, 排序列名, 目标列名, FIRST_VALUE(目标列名) OVER ( PARTITION BY 分区列名 ORDER BY 排序列名 NULLS LAST -- 将空值排在末尾,确保第一个非空值被选中 ) AS 第一个非空值 FROM 你的表名;
方法3:基于累计计数的实现
通过累计非空值的数量,标记出第一个非空值的位置,再广播到整个分区:
SELECT 分区列名, 排序列名, 目标列名, MAX(CASE WHEN 非空累计数 = 1 THEN 目标列名 END) OVER (PARTITION BY 分区列名) AS 第一个非空值 FROM ( SELECT *, SUM(CASE WHEN 目标列名 IS NOT NULL THEN 1 ELSE 0 END) OVER ( PARTITION BY 分区列名 ORDER BY 排序列名 ROWS UNBOUNDED PRECEDING ) AS 非空累计数 FROM 你的表名 ) AS 子查询;
原理:非空累计数会从0开始,第一次遇到非空值时变为1,用MAX()将该值覆盖到整个分区的所有行。
注意:以上方法均无需新增持久化列,所有计算都在窗口函数或子查询中完成,符合你的需求。
内容的提问来源于stack exchange,提问作者Zar Ha
相关产品推荐
相关产品推荐

