Как заставить LAG () игнорировать NULLS на SQL Server? - PullRequest
1 голос
/ 07 февраля 2020

Кто-нибудь знает, как заменить пустые значения в столбце на строку, пока она не достигнет новой строки, а затем эта строка заменит все нулевые значения под ней? У меня есть столбец, который выглядит следующим образом

Исходный столбец:

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

По сути, я хочу заменить первую строку в столбце все нулевые значения ниже него до следующей строки. Затем эта строка заменит все пустые значения до следующей строки и так далее.

Ответы [ 3 ]

3 голосов
/ 07 февраля 2020

SQL Сервер не поддерживает опцию ignore nulls для оконных функций, таких как lead() и lag(), для которых этот вопрос хорошо подошел.

Мы можем обойти это с некоторыми техника пробелов и островков:

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).

Демонстрация на DB Fiddle :

ID | PAST_DUE_COL            | grp | new_past_due_col       
-: | :---------------------- | --: | :----------------------
 1 | 91 or more days pastdue |   1 | 91 or more days pastdue
 2 | <em>null</em>                    |   1 | 91 or more days pastdue
 3 | <em>null</em>                    |   1 | 91 or more days pastdue
 4 | 61-90 days past due     |   2 | 61-90 days past due    
 5 | <em>null</em>                    |   2 | 61-90 days past due    
 6 | <em>null</em>                    |   2 | 61-90 days past due    
 7 | 31-60 days past due     |   3 | 31-60 days past due    
 8 | <em>null</em>                    |   3 | 31-60 days past due    
 9 | 0-30 days past due      |   4 | 0-30 days past due     
10 | <em>null</em>                    |   4 | 0-30 days past due     
11 | <em>null</em>                    |   4 | 0-30 days past due     
12 | <em>null</em>                    |   4 | 0-30 days past due     
1 голос
/ 07 февраля 2020

Это вариант ответа 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;
0 голосов
/ 07 февраля 2020

Если у вас есть столбец идентификатора, а опережение / отставание недоступны, вы можете использовать:

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