TSQL 仅在相同值之间更新 NULL
TSQL update NULLs only when between the same values
我有一个 table 需要用数据填充 NULL。但是,如果前后值相同,我只想替换 NULL。
G ID Val NewValue
a 1 N N
a 2 N N
a 3 NULL NULL -- notice this is the last value of group 'a' so keep NULL and if NULL was the first of the group, keep NULL as well
b 4 P P
b 5 N N
b 6 NULL N -- N before and N after so the new value ='N'
b 7 N N
c 8 N N
c 9 N N
c 10 NULL NULL -- N before but P after so keep NULL
c 11 P P
c 12 N N
c 13 N N
c 14 N N
d 15 P P
d 16 NULL P -- P before and P after (the series) so make 'P'
d 17 NULL P -- P before and P after (the series) so make 'P'
d 18 P P
d 19 N N
所以我有一个简单的解决方案。下面的查询给出:
- ID = 6、16 和 17 的正确结果
- ID = 3 和 10 的结果不正确
所以我的问题是剩下的怎么办?
DECLARE @Table TABLE(
G varchar(1),
ID INT,
Val varchar(2)
)
INSERT INTO @Table VALUES
('a',1,'N'),('a',2,'N'),('a',3, NULL),
('b',4,'P'),('b',5,'N'),('b',6, NULL),('b',7,'N'),
('c',8, 'N'),('c',9, 'N'),('c',10,NULL),('c',11,'P'),('c',12,'N'),('c',13,'N'),('c',14,'N'),
('d',15, 'P'),('d',16, NULL),('d',17,NULL),('d',18,'P'),('d',19,'N')
SELECT *,
CASE WHEN Val IS NULL
THEN (SELECT TOP 1 Val FROM @Table WHERE ID<T.ID AND G=T.G AND Val IS NOT NULL ORDER BY ID DESC)
ELSE Val END AS NewVal
FROM @Table T
ORDER BY G, ID
这将为您提供所需的内容减去最后一个您需要解释逻辑以及如何处理的内容。
SELECT
t.G,
t.ID,
val,
case
when val is null and
lag(val) over (partition by G order by ID) = lead(val) over (partition by G order by ID) then lag(val) over (partition by G order by ID)
else val
end as NewValue
FROM @Table T
解决问题最重要的是理解通俗易懂的英语方法。例如,在这里,您只需要找到两个最接近的非 NULL 值,最靠前的和最靠后的。当它们存在且相等时,使用它们的值。
这是将此方法翻译成 SQL:
select t.*, isnull(t.Val, case when pr.Val = nr.Val then pr.Val end) as [NewVal]
from @table t
outer apply (
select top (1) tp.Val from @table tp
where tp.G = t.G and tp.Val is not null and tp.Id < t.Id
order by tp.Id desc
) pr
outer apply (
select top (1) tn.Val from @table tn
where tn.G = t.G and tn.Val is not null and tn.Id > t.Id
order by tn.Id
) nr
order by t.g, t.Id;
我有一个 table 需要用数据填充 NULL。但是,如果前后值相同,我只想替换 NULL。
G ID Val NewValue
a 1 N N
a 2 N N
a 3 NULL NULL -- notice this is the last value of group 'a' so keep NULL and if NULL was the first of the group, keep NULL as well
b 4 P P
b 5 N N
b 6 NULL N -- N before and N after so the new value ='N'
b 7 N N
c 8 N N
c 9 N N
c 10 NULL NULL -- N before but P after so keep NULL
c 11 P P
c 12 N N
c 13 N N
c 14 N N
d 15 P P
d 16 NULL P -- P before and P after (the series) so make 'P'
d 17 NULL P -- P before and P after (the series) so make 'P'
d 18 P P
d 19 N N
所以我有一个简单的解决方案。下面的查询给出:
- ID = 6、16 和 17 的正确结果
- ID = 3 和 10 的结果不正确
所以我的问题是剩下的怎么办?
DECLARE @Table TABLE(
G varchar(1),
ID INT,
Val varchar(2)
)
INSERT INTO @Table VALUES
('a',1,'N'),('a',2,'N'),('a',3, NULL),
('b',4,'P'),('b',5,'N'),('b',6, NULL),('b',7,'N'),
('c',8, 'N'),('c',9, 'N'),('c',10,NULL),('c',11,'P'),('c',12,'N'),('c',13,'N'),('c',14,'N'),
('d',15, 'P'),('d',16, NULL),('d',17,NULL),('d',18,'P'),('d',19,'N')
SELECT *,
CASE WHEN Val IS NULL
THEN (SELECT TOP 1 Val FROM @Table WHERE ID<T.ID AND G=T.G AND Val IS NOT NULL ORDER BY ID DESC)
ELSE Val END AS NewVal
FROM @Table T
ORDER BY G, ID
这将为您提供所需的内容减去最后一个您需要解释逻辑以及如何处理的内容。
SELECT
t.G,
t.ID,
val,
case
when val is null and
lag(val) over (partition by G order by ID) = lead(val) over (partition by G order by ID) then lag(val) over (partition by G order by ID)
else val
end as NewValue
FROM @Table T
解决问题最重要的是理解通俗易懂的英语方法。例如,在这里,您只需要找到两个最接近的非 NULL 值,最靠前的和最靠后的。当它们存在且相等时,使用它们的值。
这是将此方法翻译成 SQL:
select t.*, isnull(t.Val, case when pr.Val = nr.Val then pr.Val end) as [NewVal]
from @table t
outer apply (
select top (1) tp.Val from @table tp
where tp.G = t.G and tp.Val is not null and tp.Id < t.Id
order by tp.Id desc
) pr
outer apply (
select top (1) tn.Val from @table tn
where tn.G = t.G and tn.Val is not null and tn.Id > t.Id
order by tn.Id
) nr
order by t.g, t.Id;