Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2008 从上一行的非空值更新空列值_Sql Server 2008_Tsql - Fatal编程技术网

Sql server 2008 从上一行的非空值更新空列值

Sql server 2008 从上一行的非空值更新空列值,sql-server-2008,tsql,Sql Server 2008,Tsql,@@版本1 使用SQLServer2008,我试图将值级联到列中。我有一个组id为GID和Seq的表,其中包含组内记录的排序。对于存在的列,在本例中,Name and Salary-my real表有50多列,如果它们包含NULL,我需要使用包含非NULL值的列的上一行中的值更新NULL值 下面是一些例子来说明这一点: GID Seq Name Salary 1 1 James NULL 1 2 NULL 100 1 3 NULL NULL 2

@@版本1

使用SQLServer2008,我试图将值级联到列中。我有一个组id为GID和Seq的表,其中包含组内记录的排序。对于存在的列,在本例中,Name and Salary-my real表有50多列,如果它们包含NULL,我需要使用包含非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为@Version 1提供的解决方案。我对这个问题做了一点补充。Seq列中的起始编号可以是0或1。在第一个问题的解决方案中,递归CTE中的锚引用1,如果它是1或0呢?在这个版本中,最后3行数据GID=4被添加到上述三个代码块中

谢谢

这个怎么样

;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
对于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

Karthik-当你可以直接问eric时,你不觉得这个问题有点可笑吗?你能编辑并发布一个@版本以防答案变得那么具体吗?我很久以前已经问过eric先生了,你不记得了吗?已添加版本。谢谢GilM!你的解决方案是有效的,我知道它将是一个递归的CTE,但我还没有充分理解它来编写它。我已经更新了:从@Test中选择GID,SEQ,Name,Salary,其中SEQ=1,从@Test中选择T.GID,T.SEQ,Name,Salary,从@Test中选择GID,在T.GID=S.GID和T.SEQ=S.SEQ上选择MINSeq,从@Test中选择GID,T.SEQ,Name,Salary。更新旨在解决我问题的@Version 2。有更好的选择吗?我想您也可以将WHERE SEQ=1替换为WHERE SEQ=SELECT MINSEQ FROM@Test t2 WHERE t2.GID=t1.GID。此外,您还需要将t1别名添加到上面的。此外,如果GID的SEQ值可能超过100个,则应添加选项MAXRECURSION 0。我认为这会起作用,但尚未测试,但由于OP说实际表有50多列,每列都有一个子查询似乎不切实际。@GilM我同意50列是不切实际的:。添加了一个版本,允许更少的键入,并可能表现更好。只要您能保证Seq确实是顺序的,您的版本就可以正常工作。很好!我不知道它是如何执行的,但它很有创意。@MikaelEriksson我确实可以保证Seq是顺序的,它是由一个行数生成的,我只是不想在示例中增加额外的复杂性。
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