在SQL Server中使用IGNORE NULLS的Last_value

时间:2017-07-03 21:18:06

标签: c# sql sql-server

我有一个空值的时间序列。我想用最新的非非值替换每个空值。根据我的研究,Oracle SQL可以使用Last_value和IGNORE NULLS轻松完成此任务。有没有类似的方法来使用SQL Server 2016实现这一目标?否则我只是想用C#编写代码,但感觉使用SQL会更快,更干净,更容易。

Sec SCORE
1   Null
2   Null
3   5
4   Null
5   8
6   7
7   Null

应替换为:

Sec SCORE
1   Null
2   Null
3   5
4   5
5   8
6   7
7   7

2 个答案:

答案 0 :(得分:5)

您可以通过两次累积操作来完成此操作:

select t.*,
       coalesce(score, max(score) over (partition by id)) as newscore
from (select t.*,
             max(case when score is not null then id end) over (order by id) as maxid
      from t
     ) t;

最里面的子查询获取有值的最新id。最外面的一个“将”值“扩展”到后续行。

如果您确实想要更新表格,可以轻松地将其合并到update中。但是,Oracle不能(轻松)做到这一点,所以我猜这不是必要的。

答案 1 :(得分:3)

如果性能是一个问题,我建议本文提供解决方案:

The Last non NULL Puzzle

他的最终解决方案虽然密集,但在没有任何联接的线性查询计划下确实表现出色。这是我使用的示例实现,该实现通过type2 scd登台表携带了最后一个客户名称。在此登台表中,NULL表示不进行更新,而'*** DELETED ***'表示显式设置为NULL。以下内容将其清理得非常类似于实际的SCD记录:

WITH [SampleNumbered] AS (
    SELECT  *, ROW_NUMBER() OVER ( PARTITION BY [SampleId] ORDER BY [StartDatetime] ) AS [RowNumber]
    FROM [dbo].[SampleDimStage]
), [SamplePrep] AS (
    SELECT  [SampleId]
        ,   [StartDatetime]
        ,   CAST([RowNumber] AS BINARY(8)) + CAST([SampleGroupId] AS VARBINARY(255)) AS [BinarySampleGroupId]
        ,   CAST([RowNumber] AS BINARY(8)) + CAST([SampleStatusCode] AS VARBINARY(255)) AS [BinarySampleStatusCode]
    FROM [SampleNumbered]
), [SampleCleanUp] AS (
    SELECT  [SampleId]
        ,   [StartDatetime]
        ,   CAST(SUBSTRING(MAX([BinarySampleGroupId]) OVER( PARTITION BY [SampleId] ORDER BY [StartDatetime] )
                , 9, 255) AS VARCHAR(255)) AS [LastSampleGroupId]
        ,   CAST(SUBSTRING(MAX([BinarySampleStatusCode]) OVER( PARTITION BY [SampleId] ORDER BY [StartDatetime] )
                , 9, 255) AS VARCHAR(255)) AS [LastSampleStatusCode]
        ,   LEAD([StartDatetime]) OVER( PARTITION BY [SampleId] ORDER BY [StartDatetime] ) AS [EndDatetime]
    FROM [SamplePrep]
)
SELECT  CAST([SampleId] AS NUMERIC(18)) AS [SampleId]
    ,   CAST(NULLIF([sc].[LastSampleGroupId],'*** DELETED ***') AS NUMERIC(18)) AS [GroupId]
    ,   CAST(NULLIF([sc].[LastSampleStatusCode],'*** DELETED ***') AS CHAR(3)) AS [SampleStatusCode]
    ,   [StartDatetime]
    ,   [sc].[EndDatetime]
FROM [SampleCleanUp] [sc];

如果您的排序键是某种整数,则可以完全跳过第一个CTE并将其直接转换为二进制。