首页 > 解决方案 > 如果为 Null,则 HOLD 先前的非 Null 值

问题描述

我正在使用 SQL Server。我想用前一个(最后一个)非空值替换表中的所有 NULLS,以填补数据中的 NULL 空白。例如,假设我有一个表,其中一些值为 NULL:

DECLARE @Table TABLE(
        dt datetime2(0),
        v1 INT,
        v2 INT,
        v3 INT,
        v4 INT,
        v5 INT,
        v999 INT
)

INSERT INTO @Table (dt,v1,v2,v3,v4,v5,v999) SELECT '6/12/2021 03:45', 3, 4, 8, 5, NULL, 2
INSERT INTO @Table (dt,v1,v2,v3,v4,v5,v999) SELECT '6/12/2021 03:46', 9, NULL, 2, NULL, 1, 0
INSERT INTO @Table (dt,v1,v2,v3,v4,v5,v999) SELECT '6/12/2021 03:47', 5, 2, NULL, 7, 8, NULL
INSERT INTO @Table (dt,v1,v2,v3,v4,v5,v999) SELECT '6/12/2021 03:48', 9, 0, NULL, 6, 6, NULL
INSERT INTO @Table (dt,v1,v2,v3,v4,v5,v999) SELECT '6/12/2021 03:49', NULL, 7, 0, 0, 3, NULL
INSERT INTO @Table (dt,v1,v2,v3,v4,v5,v999) SELECT '6/12/2021 03:50', 6, 2, 7, 3, NULL, NULL

桌子:

桌子

但是假设我有大约 200 万行和大约 200 列。

我已经为每一列尝试了 SELECT 语句,但速度非常慢。我也尝试过使用 UPDATE 语句(也使用 SELECT),它非常慢。我找不到 SQL Server 的 LAST_VALUE 和 IGNORE NULLS 的良好替代方案。您对如何用大量行和列的最后一个非空值替换 NULLS 有任何想法吗?

编辑:我希望结果看起来像这样,其中先前的非空值将填充每列的任何计算的空值:

结果

我为每一列尝试了更新语句,但查询速度很慢。它们是这样的,但我尝试了几种。使用 Select 的所有尝试都非常慢。

UPDATE #table SET v1 = (SELECT TOP 1 u.v1 FROM #table u WHERE u.v1 is not null AND u.dt <= #table.dt ORDER BY u.dt DESC)

编辑#2:为了清楚问题而进行了编辑,因为我希望在列中的 NULL 间隙中“保留最后一个非值”。

标签: sqlsql-serversql-null

解决方案


没有简单、便宜的方法可以做到这一点。部分问题在于您的数据模型。有这么多列是非常可疑的。而且,更糟糕的是,他们似乎有相似的数据。它们可能应该存储在不同的行中。

你能做什么?好吧,你可以这样做:

with toupdate as (
      select t.*,
             first_value(v1) over (order by (case when v1 is not null then 1 else 2 end), dt desc) as last_v1,
             first_value(v2) over (order by (case when v2 is not null then 1 else 2 end), dt desc) as last_v2,
             . . .
      from t
     )
update toupdate
    set v1 = coalesce(v1, last_v1),
        v2 = coalesce(v2, last_v2),
        . . . ;

我提醒您,更新大表中的所有行需要很长时间。但这是表达查询的一种相对简单的方式。

请注意,SQL Server 确实对查询或结果集中的列数有限制,因此这不适用于任意数量的列。


推荐阅读