【问题标题】:replace NULL values with latest non-NULL value in resultset series (SQL Server 2008 R2)用结果集系列中的最新非 NULL 值替换 NULL 值(SQL Server 2008 R2)
【发布时间】:2011-10-26 01:55:12
【问题描述】:

对于 SQL Server 2008 R2

我有一个看起来像这样的结果集(注意 [price] 是数字,下面的 NULL 表示 NULL值,结果集按product_id和timestamp排序)

product timestamp          price 
------- ----------------   -----
   5678 2008-01-01 12:00   12.34
   5678 2008-01-01 12:01    NULL
   5678 2008-01-01 12:02    NULL
   5678 2008-01-01 12:03   23.45
   5678 2008-01-01 12:04    NULL

我想将其转换为一个结果集,该结果集(实质上)从最新的前一行复制一个非空值,以生成如下所示的结果集:

product timestamp          price  
------- ----------------   -----
   5678 2008-01-01 12:00   12.34
   5678 2008-01-01 12:01   12.34
   5678 2008-01-01 12:02   12.34
   5678 2008-01-01 12:03   23.45
   5678 2008-01-01 12:04   23.45

我没有找到任何允许我执行此操作的聚合/窗口函数(同样只有 SQL Server 2008 R2 需要此功能。)

我希望找到一个分析聚合函数来为我做这件事,比如......

LAST_VALUE(price) OVER (PARTITION BY product_id ORDER BY timestamp)

但我似乎没有找到任何方法在窗口中执行“累积最新非空值”(将窗口绑定到前面的行,而不是整个分区)

除了创建一个表值的用户定义函数之外,是否有任何内置函数可以完成此操作?


更新:

显然,此功能在“Denali”CTP 中可用,但在 SQL Server 2008 R2 中不可用。

LAST_VALUE http://msdn.microsoft.com/en-us/library/hh231517%28v=SQL.110%29.aspx

我只是希望它在 SQL Server 2008 中可用。它在 Oracle 中可用(至少从 10gR2 开始),我可以在 MySQL 5.1 中使用局部变量执行类似的操作。

http://download.oracle.com/docs/cd/E14072_01/server.112/e10592/functions083.htm

【问题讨论】:

  • 您的意思是哪个功能在 Denali 中可用,但在 2008 R2 中不可用??

标签: sql-server aggregate-functions sql-server-2008-r2 analytic-functions


【解决方案1】:

我有一个包含以下数据的表格。我想用以前的值更新薪水列中的所有空值而不取空值。

表:

id  name    salary
1   A       4000
2   B   
3   C   
4   C   
5   D       2000
6   E   
7   E   
8   F       1000
9   G       2000
10  G       3000
11  G       5000
12  G   

这是适合我的查询。

select a.*,first_value(a.salary)over(partition by a.value order by a.id) as abc from
(
     select *,sum(case when salary is null then 0 else 1 end)over(order by id) as value from test)a

输出:

id  name    salary  Value   abc
1   A       4000    1     4000
2   B               1     4000
3   C               1     4000
4   C               1     4000
5   D       2000    2     2000
6   E               2     2000
7   E               2     2000
8   F       1000    3     1000
9   G       2000    4     2000
10  G       3000    5     3000
11  G       5000    6     5000
12  G               6     5000

【讨论】:

    【解决方案2】:

    您可以尝试以下方法:

    * 更新**

    -- Test Data
    DECLARE @YourTable TABLE(Product INT, Timestamp DATETIME, Price NUMERIC(16,4))
    
    INSERT INTO @YourTable
    SELECT 5678, '20080101 12:00:00', 12.34
    UNION ALL
    SELECT 5678, '20080101 12:01:00', NULL
    UNION ALL
    SELECT 5678, '20080101 12:02:00', NULL
    UNION ALL
    SELECT 5678, '20080101 12:03:00', 23.45
    UNION ALL
    SELECT 5678, '20080101 12:04:00', NULL
    
    ;WITH CTE AS
    (
        SELECT *
        FROM @YourTable
    )
    
    -- Query
    SELECT A.Product, A.Timestamp, ISNULL(A.Price,B.Price) Price
    FROM CTE A
    OUTER APPLY (   SELECT TOP 1 *
                    FROM CTE 
                    WHERE Product = A.Product AND Timestamp < A.Timestamp
                    AND Price IS NOT NULL
                    ORDER BY Product, Timestamp DESC) B
    
    --Results
    Product Timestamp   Price
    5678    2008-01-01 12:00:00.000 12.3400
    5678    2008-01-01 12:01:00.000 12.3400
    5678    2008-01-01 12:02:00.000 12.3400
    5678    2008-01-01 12:03:00.000 23.4500
    5678    2008-01-01 12:04:00.000 23.4500
    

    【讨论】:

    • APPLY 关键字对我来说是新的。我会试一试。谢谢!
    • @spencer7593 - 告诉我进展如何。
    • @spencer7593 - 此外,您可以在此链接上找到有关 APPLY 运算符的一些文档:technet.microsoft.com/en-us/library/ms175156.aspx
    • 行源比@YourTable 更复杂...我宁愿只指定行源一次。是否可以使用公用表表达式 WITH cte AS (SELECT * FROM @YourTable) SELECT ... 重写
    • @spencer7593 - 好的,我更改查询,使其使用CTE
    【解决方案3】:

    试试这个:

    ;WITH SortedData AS
    (
        SELECT
           ProductID, TimeStamp, Price,
           ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY TimeStamp DESC) AS 'RowNum'
        FROM dbo.YourTable
    )
    UPDATE SortedData
    SET Price = (SELECT TOP 1 Price 
                 FROM SortedData sd2
             WHERE sd2.RowNum > SortedData.RowNum 
               AND sd2.Price IS NOT NULL)
    WHERE
        SortedData.Price IS NULL
    

    基本上,CTE 创建一个按时间戳(降序)排序的列表 - 最新的在前。每当找到 NULL 时,将找到包含 NOT NULL 价格的下一行,并且该值用于更新具有 NULL 价格的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多