@@ Version 1
使用SQL Server 2008,我试图将值级联到列中。我有一个包含组ID(GID)和Seq的表,其中包含组内记录的排序。对于存在的列,在本例中为Name和Salary - 我的真实表有超过50列,如果它们包含NULL,我需要使用包含非空值的该列的前一行的值更新NULL值。
这可以用来说明这一点:
GID Seq Name Salary
1 1 James NULL
1 2 NULL 100
1 3 NULL NULL
2 1 NULL 81
2 2 Smith NULL
2 3 NULL NULL
3 1 Charles NULL
3 2 NULL NULL
3 3 Brown NULL
3 4 NULL 75
4 0 Ron 50
4 1 NULL 20
4 2 NULL NULL
我的结果应该是:
GID Seq Name Salary
1 1 James NULL
1 2 James 100
1 3 James 100
2 1 NULL 81
2 2 Smith 81
2 3 Smith 81
3 1 Charles NULL
3 2 Charles NULL
3 3 Brown NULL
3 4 Brown 75
4 0 Ron 50
4 1 Ron 20
4 2 Ron 20
我希望在不使用动态SQL,循环或游标的情况下执行此操作。
简单测试用例的代码:
DECLARE @Test TABLE (GID int, Seq int, Name varchar(50), Salary decimal)
INSERT INTO @Test VALUES (1, 1, 'James', NULL)
INSERT INTO @Test VALUES (1, 2, NULL, 100.40)
INSERT INTO @Test VALUES (1, 3, NULL, NULL)
INSERT INTO @Test VALUES (2, 1, NULL, 80.50)
INSERT INTO @Test VALUES (2, 2, 'Smith', NULL)
INSERT INTO @Test VALUES (2, 3, NULL, NULL)
INSERT INTO @Test VALUES (3, 1, 'Charles', NULL)
INSERT INTO @Test VALUES (3, 2, NULL, NULL)
INSERT INTO @Test VALUES (3, 3, 'Brown', NULL)
INSERT INTO @Test VALUES (3, 4, NULL, 75)
INSERT INTO @Test VALUES (4, 0, 'Ron', 50)
INSERT INTO @Test VALUES (4, 1, NULL, 20)
INSERT INTO @Test VALUES (4, 2, NULL, NULL)
SELECT * FROM @Test
@@版本2 感谢GilM为@@版本1提供解决方案。我对此问题做了一些补充。 Seq列中的起始编号可以是0或1.在第一个问题的解决方案中,递归CTE中的锚点引用1,如果它是1或0怎么办?最后3行数据(GID = 4)被添加到此版本中的所有上述三个代码块中。
谢谢!
答案 0 :(得分:2)
这个怎么样?:
;WITH CTE AS (
SELECT GID, SEQ, Name, Salary
FROM @Test t1
WHERE SEQ = (SELECT MIN(SEQ) FROM @Test t2 WHERE t2.GID = t1.GID)
UNION ALL
SELECT t.GID, t.SEQ, COALESCE(t.Name,c.Name), COALESCE(t.Salary,c.Salary)
FROM CTE c
JOIN @Test t ON t.GID = c.GID AND t.SEQ = c.SEQ+1
)
UPDATE t SET
Name = c.Name,
Salary = c.Salary
FROM @Test t
JOIN CTE c ON c.GID = t.GID AND c.Seq = t.SEQ
答案 1 :(得分:1)
update T set
Name = (
select top(1) T1.Name
from @Test as T1
where T1.GID = T.GID and
T1.Seq <= T.Seq and
T1.Name is not null
order by T1.Seq desc
),
Salary = (
select top(1) T1.Salary
from @Test as T1
where T1.GID = T.GID and
T1.Seq <= T.Seq and
T1.Salary is not null
order by T1.Seq desc
)
from @Test as T
where T.Name is null or
T.Salary is null
有50列会有很多打字和很多相关的子查询。
这是一个使用XML的版本。较少的打字和性能可以更好。
with C as
(
select GID,
(
select *
from @Test as T2
where T1.GID = T2.GID
order by T2.Seq desc
for xml path('row'), type
) as X
from @Test as T1
group by GID
)
update T set
Name = C.X.value('(/row[Seq<=sql:column("T.Seq")]/Name)[1]', 'varchar(50)'),
Salary = C.X.value('(/row[Seq<=sql:column("T.Seq")]/Salary)[1]', 'decimal')
from @Test as T
inner join C
on T.GID = C.GID