6

如何告诉 LAG 函数获取最后一个“非空”值?

例如,请参阅下面的表格,其中 B 列和 C 列上有一些 NULL 值。我想用最后一个非空值填充空值。我试图通过使用 LAG 函数来做到这一点,如下所示:

case when B is null then lag (B) over (order by idx) else B end as B,

但是当我在一行中有两个或更多空值时,这并不完全有效(请参阅 C 列第 3 行的 NULL 值 - 我希望它是原始值的 0.50)。

知道如何实现吗?(它不一定要使用 LAG 功能,欢迎任何其他想法)

几个假设:

  • 行数是动态的;
  • 第一个值总是非空的;
  • 一旦我有一个 NULL,到最后都是 NULL - 所以我想用最新的值填充它。

谢谢

在此处输入图像描述

4

5 回答 5

7

您可以使用outer apply操作员来做到这一点:

select t.id,
       t1.colA,
       t2.colB,
       t3.colC 
from table t
outer apply(select top 1 colA from table where id <= t.id and colA is not null order by id desc) t1
outer apply(select top 1 colB from table where id <= t.id and colB is not null order by id desc) t2
outer apply(select top 1 colC from table where id <= t.id and colC is not null order by id desc) t3;

无论空值或空“岛”的数量如何,这都会起作用。您可能有值,然后是空值,然后是值,又是空值。它仍然可以工作。


但是,如果假设(在您的问题中)成立:

一旦我有了NULL, 就NULL到最后了 - 所以我想用最新的值填充它。

有一个更有效的解决方案。我们只需要找到最新的(按 排序时idx)值。修改上述查询,where id <= t.id从子查询中删除:

select t.id,
       colA = coalesce(t.colA, t1.colA),
       colB = coalesce(t.colB, t2.colB),
       colC = coalesce(t.colC, t3.colC) 
from table t
outer apply (select top 1 colA from table 
             where colA is not null order by id desc) t1
outer apply (select top 1 colB from table 
             where colB is not null order by id desc) t2
outer apply (select top 1 colC from table 
             where colC is not null order by id desc) t3;
于 2016-04-25T10:41:46.417 回答
4

您可以对您的 , 进行更改ORDER BY,以强制 NULL 在您的排序中排在第一位,但这可能会很昂贵......

lag(B) over (order by CASE WHEN B IS NULL THEN -1 ELSE idx END)

或者,使用子查询计算一次替换值。在较大的套装上可能更便宜,但非常笨重。
- 依赖于最后出现的所有 NULL
- LAG 不依赖于它

COALESCE(
    B,
    (
        SELECT
            sorted_not_null.B
        FROM
        (
            SELECT
                table.B,
                ROW_NUMBER() OVER (ORDER BY table.idx DESC)   AS row_id
            FROM
                table
            WHERE
                table.B IS NOT NULL
        )
           sorted_not_null
        WHERE
           sorted_not_null.row_id = 1
    )
)

(这在较大的数据集上应该比相关子查询更快LAGOUTER APPLY因为该值只计算一次。为了整洁,您可以计算并存储变量中每列的 [last_known_value],然后只需使用COALESCE(A, @last_known_A), COALESCE(B, @last_known_B), etc

于 2016-04-25T10:40:45.590 回答
1

如果它一直为空,那么可以走捷径

declare @b varchar(20) = (select top 1 b from table where b is not null order by id desc);
declare @c varchar(20) = (select top 1 c from table where c is not null order by id desc); 
select is, isnull(b,@b) as b, insull(c,@c) as c 
from table;
于 2016-04-25T12:10:15.907 回答
1
Select max(diff) from(
Select 
    Case when lag(a) over (order by b) is not null
    Then (a -lag(a) over (order by b)) end as diff 
     From <tbl_name> where
    <relevant conditions>
    Order by b) k

在 db 可视化器中工作正常。

于 2021-03-26T10:39:15.440 回答
-3
UPDATE table 
SET B = (@n := COALESCE(B , @n))
WHERE B is null;
于 2016-04-25T10:57:11.233 回答