SQL查询根据不同的情况将值分配给其他行中具有空值的列

时间:2019-01-18 23:39:48

标签: sql sql-server

我有以下实际生产数据场景,我正在尝试获得所需的输出。我必须从其他行(基于数据的下一个或上一个)中填充Worker的所有NULL值。

样本输入

PK  Id  Status      Worker      Created Date
--- --- ----------- ----------- -------------
1   101 Waiting     NULL        1/1/2019 8:00
2   101 Assigned    Jon Doe     1/1/2019 8:10
3   101 Initiated   Jon Doe     1/1/2019 8:15    
4   102 Waiting     NULL        1/1/2019 8:00
5   102 Waiting     NULL        1/1/2019 8:12
6   102 Assigned    Jane Doe    1/1/2019 8:15
7   103 Waiting     NULL        1/1/2019 8:00
9   103 Initiated   Jon Doe     1/1/2019 8:15
11  103 Waiting     NULL        1/1/2019 8:17
12  103 Assigned    Jane Doe    1/1/2019 8:20
13  103 Assigned    NULL        1/1/2019 8:22
14  103 Initiated   NULL        1/1/2019 8:25

所需的输出

PK  Id  Status      Worker      Created Date
--- --- ----------- ----------- -------------
1   101 Waiting     Jon Doe     1/1/2019 8:00
2   101 Assigned    Jon Doe     1/1/2019 8:10
3   101 Initiated   Jon Doe     1/1/2019 8:15    
4   102 Waiting     Jane Doe    1/1/2019 8:00
5   102 Waiting     Jane Doe    1/1/2019 8:12
6   102 Assigned    Jane Doe    1/1/2019 8:15
7   103 Waiting     Jon Doe     1/1/2019 8:00
9   103 Initiated   Jon Doe     1/1/2019 8:15
11  103 Waiting     Jane Doe    1/1/2019 8:17
12  103 Assigned    Jane Doe    1/1/2019 8:20
13  103 Assigned    Jane Doe    1/1/2019 8:22
14  103 Initiated   Jane Doe    1/1/2019 8:25

SQL:

select tl.*, RANK() OVER (ORDER BY tl.[Id],tl.[Created Date]) rnk 
into #temp 
from table tl

select tl.*, 
       case when tl.[Worker] is null t2.[Worker] else tl.[Worker] end as [Worker Updated]
from #temp tl
left join #temp t2 on tl.[Id]=t2.[Id] and tl.rnk=t2.rnk-1

我只能在输入数据样本中获得方案ID 101的正确结果。我不知道如何处理方案102(连续两行在Worker列上为NULL)和103(最后两行在Worker上都为NULL)。

有人可以帮我吗?

2 个答案:

答案 0 :(得分:1)

我认为您需要的是ISNULL()MAX() OVER(),因此您的查询将具有以下内容:

SELECT  
    t1.PK
,   t1.Id
,   t1.Status
,   ISNULL(t1.Worker, MAX(t1.Worker) OVER(PARTITION BY Id) ) Worker
,   t1.CreatedDate
FROM #temp tl

ISNULL()将检查该值,如果为null,则将其替换为辅助值。与查询中的情况相同。

MAX(t1.Worker) OVER(PARTITION BY Id)

由于聚合函数消除了空值,因此我们利用了这一优势,并将其与OVER()子句一起使用,可以按Id对行进行分区,并使用其中一个聚合函数获得所需的值。

答案 1 :(得分:0)

可能最简单的方法是outer apply

select t.id, t.status, t2.worker, t.date
from t outer apply
     (select top (1) t2.*
      from t2
      where t2.worker is not null and t2.id >= t.id
      order by t2.id asc
     ) t2;

您真正想要的是IGNORE NULLS上的LEAD()选项。但是,SQL Server不支持。

如果要在之前的值中填入最新的值,请对另一个apply使用相同的逻辑:

select t.id, t.status,
       coalesce(tnext.worker, tprev.worker) as worker, t.date
from t outer apply
     (select top (1) t2.*
      from t2
      where t2.worker is not null and t2.id >= t.id
      order by t2.id asc
     ) tnext outer apply
     (select top (1) t2.*
      from t2
      where t2.worker is not null and t2.id <= t.id
      order by t2.id desc
     ) tprev;