【问题标题】:get the value from the previous row if row is NULL如果 row 为 NULL,则从上一行获取值
【发布时间】:2015-07-21 11:58:07
【问题描述】:

我有这个透视表

+---------+----------+----------+-----+----------+
| Date    | Product1 | Product2 | ... | ProductN |
+---------+----------+----------+-----+----------+
| 7/1/15  | 5        | 2        | ... | 7        |
| 8/1/15  | 7        | 1        | ... | 9        |
| 9/1/15  | NULL     | 7        | ... | NULL     |
| 10/1/15 | 8        | NULL     | ... | NULL     |
| 11/1/15 | NULL     | NULL     | ... | NULL     |
+---------+----------+----------+-----+----------+

我想用上面的值填写NULL 列。所以,输出应该是这样的。

+---------+----------+----------+-----+----------+
| Date    | Product1 | Product2 | ... | ProductN |
+---------+----------+----------+-----+----------+
| 7/1/15  | 5        | 2        | ... | 7        |
| 8/1/15  | 7        | 1        | ... | 9        |
| 9/1/15  | 7        | 7        | ... | 9        |
| 10/1/15 | 8        | 7        | ... | 9        |
| 11/1/15 | 8        | 7        | ... | 9        |
+---------+----------+----------+-----+----------+

我发现这个article 可能对我有帮助,但这只是操纵一列。我如何将此应用于我的所有列,或者由于我的列是动态的,我如何才能获得这样的结果。

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 我的猜测是在旋转之前执行此操作会容易得多。
  • 是的。但我找不到任何方法来确定NULL 列是什么
  • 这是原始数据中不存在的行(假设您实际上没有NULL值)
  • 可以确定哪些行不存在?一个例子将是一个很好的参考。
  • 这取决于您的数据,但例如stackoverflow.com/questions/25038494/… 有一些想法。您还可以考虑创建一个日历表(每天 1 行),它通常有助于与日历相关的查询

标签: sql sql-server tsql null


【解决方案1】:

ANSI 标准在LAG() 上有IGNORE NULLS 选项。这正是你想要的。唉,SQL Server 还没有(还没有)实现这个功能。

因此,您可以通过多种方式做到这一点。一种是使用多个outer applys。另一个使用相关子查询:

select p.date,
       (case when p.product1 is not null else p.product1
             else (select top 1 p2.product1 from pivoted p2 where p2.date < p.date order by p2.date desc)
        end) as product1,
       (case when p.product1 is not null else p.product1
             else (select top 1 p2.product1 from pivoted p2 where p2.date < p.date order by p2.date desc)
        end) as product1,
       (case when p.product2 is not null else p.product2
             else (select top 1 p2.product2 from pivoted p2 where p2.date < p.date order by p2.date desc)
        end) as product2,
       . . .
from pivoted p ;

我会为此查询推荐date 上的索引。

【讨论】:

  • 嗨。你将如何动态地做到这一点?因为我不知道Products是什么。
  • @BoyPasmo 。 . .那将是一个非常不同的问题。我建议您提出问题包括您用于枢轴的代码。
【解决方案2】:

我想建议您一个解决方案。如果您的表格仅包含两列,我的解决方案将完美运行。

+---------+----------+
| Date    | Product  |
+---------+----------+
| 7/1/15  | 5        |
| 8/1/15  | 7        |
| 9/1/15  | NULL     |
| 10/1/15 | 8        |
| 11/1/15 | NULL     |
+---------+----------+

select  x.[Date], 
        case
            when x.[Product] is null
            then min(c.[Product])
        else
            x.[Product]
        end as Product
from
(
    -- this subquery evaluates a minimum distance to the rows where Product column contains a value
    select  [Date], 
            [Product], 
            min(case when delta >= 0 then delta else null end) delta_min,
            max(case when delta < 0 then delta else null end) delta_max
    from
    (
        -- this subquery maps Product table to itself and evaluates the difference between the dates
        select  p.[Date],
                p.[Product], 
                DATEDIFF(dd, p.[Date], pnn.[Date]) delta
        from @products p
        cross join (select * from @products where [Product] is not null) pnn
    ) x
    group by [Date], [Product]
) x
left join @products c on x.[Date] = 
    case
        when abs(delta_min) < abs(delta_max) then DATEADD(dd, -delta_min, c.[Date]) 
        else DATEADD(dd, -delta_max, c.[Date])
    end
group by x.[Date], x.[Product]
order by x.[Date]

在这个查询中,我通过 CROSS JOIN 语句将表映射到包含值的自身行。然后我计算了日期之间的差异,以便选择最接近的日期,然后用值填充空单元格。

结果:

+---------+----------+
| Date    | Product  |
+---------+----------+
| 7/1/15  | 5        |
| 8/1/15  | 7        |
| 9/1/15  | 7        |
| 10/1/15 | 8        |
| 11/1/15 | 8        |
+---------+----------+

实际上,建议的查询不会选择先前的值。取而代之的是,它选择最接近的值。换句话说,我的代码可以用于许多不同的目的。

【讨论】:

    【解决方案3】:
    First You need to add identity column in temporary or hard table then resolved by following method.
    
    --- Solution ----
    
    Create Table #Test (ID Int Identity (1,1),[Date] Date , Product_1 INT )
    
    Insert Into #Test ([Date], Product_1)
    Values
    ('7/1/15',5)
    ,('8/1/15',7)
    ,('9/1/15',Null)
    ,('10/1/15',8)
    ,('11/1/15',Null)
    
    
    Select ID , DATE , 
    IIF ( Product_1 is null ,
    (Select Product_1 from #TEST
    Where ID = (Select Top 1 a.ID From #TEST a where a.Product_1 is not null and a.ID<b.ID
    Order By a.ID desc)
    ),Product_1) Product_1
    from #Test b
    
    
    -- Solution End ---
    

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 2016-01-09
    • 2016-05-23
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多