【问题标题】:How to make LAG() ignore NULLS in SQL Server?如何让 LAG() 在 SQL Server 中忽略 NULLS?
【发布时间】:2020-05-23 03:11:28
【问题描述】:

有谁知道如何用字符串替换列中的空值,直到它遇到一个新字符串,然后该字符串替换它下面的所有空值?我有一个看起来像这样的列

原始栏目:

PAST_DUE_COL           
91 or more days pastdue        
Null
Null
61-90 days past due          
Null
Null
31-60 days past due
Null
0-30 days past due
Null       
Null
Null            

预期结果栏:

PAST_DUE_COL           
91 or more days past due        
91 or more days past due
91 or more days past due
61-90 days past due          
61-90 days past due 
61-90 days past due 
31-60 days past due
31-60 days past due
0-30 days past due
0-30 days past due      
0-30 days past due
0-30 days past due

基本上我希望列中的第一个字符串替换它下面的所有空值,直到下一个字符串。然后该字符串将替换它下面的所有空值,直到下一个字符串,依此类推。

【问题讨论】:

  • 你需要一列order记录。
  • @Ryan 只是检查您是否了解有关接受答案的网站礼仪?习惯上通过单击相关答案旁边的复选标记来“接受”最能解决您的问题的答案(这与赞成投票是分开的)。我注意到尽管提出了很多问题,但您从未接受过答案。我强烈建议您这样做,因为它是网站的运作方式,如果您从不接受任何答案,人们可​​能会不愿意回答您的问题。
  • 嘿,谢谢你指出我不完全确定它是如何工作的,但我检查了我的旧答案并检查了它们。这里的每个人都非常乐于助人,我想确保在信用到期时有信用。

标签: sql sql-server window-functions gaps-and-islands sql-null


【解决方案1】:

SQL Server 不支持lead()lag() 等窗口函数的ignore nulls 选项,这个问题非常适合。

我们可以通过一些差距和孤岛技术来解决这个问题:

select
    t.*,
    max(past_due_col) over(partition by grp) new_past_due_col
from (
    select 
        t.*,
        sum(case when past_due_col is null then 0 else 1 end)
            over(order by id) grp
    from mytable t
) t

每次找到非空值时,子查询都会执行一个窗口求和:这定义了包含非空值后跟空值的行组。

然后,外部使用窗口max() 来检索每个组中的(唯一)非空值。

这假定可以使用一列对记录进行排序(我称之为id)。

Demo on DB Fiddle

身份证 | PAST_DUE_COL | grp | new_past_due_col -: | :------------------------ | --: | :------------------------ 1 |逾期 91 天或更长时间 | 1 |逾期 91 天或以上 2 | | 1 |逾期 91 天或以上 3 | | 1 |逾期 91 天或以上 4 |逾期 61-90 天 | 2 |逾期 61-90 天 5 | | 2 |逾期 61-90 天 6 | | 2 |逾期 61-90 天 7 |逾期 31-60 天 | 3 |逾期 31-60 天 8 | | 3 |逾期 31-60 天 9 |逾期 0-30 天 | 4 |逾期 0-30 天 10 | | 4 |逾期 0-30 天 11 | | 4 |逾期 0-30 天 12 | | 4 |逾期 0-30 天

【讨论】:

    【解决方案2】:

    这是 GMB 答案的变体。就是简单一点:

    select t.*,
           max(past_due_col) over(partition by grp) as new_past_due_col
    from (select t.*,
                 count(past_due_col) over (order by id) as grp
          from mytable t
         ) t;
    

    请注意,您需要某种排序列才能使您的问题有意义。

    另一种方法使用apply

    select t.*, t2.past_due_col
    from mytable t outer apply
         (select top (1) t2.*
          from mytable t2
          where t2.id <= t.id and t2.past_due_col is not null
          order by t2.id desc
         ) t2;
    

    【讨论】:

    • 这是我在这里找到的最简单的解决方案。
    【解决方案3】:

    如果您有一个 id 列并且领先/滞后不可用,您可以使用:

      SELECT (select top 1 PAST_DUE_COL from MyTablename 
        where id <= t.id and PAST_DUE_COL <> '' order by id desc)
        FROM MyTablename T
    

    【讨论】:

      猜你喜欢
      • 2022-11-23
      • 2016-08-18
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      相关资源
      最近更新 更多