UPDATE FROM不能与同一行的多次更新一起使用

时间:2015-05-25 14:01:47

标签: sql sql-server sql-server-2012

我有@Products和@TempProducts表。我想从@TempProducts更新@Products。

我的代码:

DECLARE @Products TABLE(
  Id INT, 
  Name NVARCHAR(255), 
  Description NVARCHAR(255));

DECLARE @TempProducts TABLE(
  RowNumber int, 
  Id INT, 
  Name NVARCHAR(255), 
  Description NVARCHAR(255));

INSERT INTO @Products(Id,Name,Description) VALUES(1,'Name1','Desc1');

INSERT INTO @TempProducts(RowNumber,Id,Name,Description)
  VALUES(1,1,'NewName1',NULL);
INSERT INTO @TempProducts(RowNumber,Id,Name,Description)
  VALUES(2,1,NULL,'NewDesc1');
INSERT INTO @TempProducts(RowNumber,Id,Name,Description)
  VALUES(3,1,NULL,'NewDesc2');
INSERT INTO @TempProducts(RowNumber,Id,Name,Description)
  VALUES(4,1,'NewName2',NULL);

WITH TP AS
(
    SELECT TOP (100000) RowNumber,Id,Name,DESCRIPTION 
    FROM @TempProducts 
    ORDER BY RowNumber ASC
)
UPDATE  P
   SET  Name = ISNULL(TP.Name,P.Name),
        Description = ISNULL(TP.Description,P.Description)
FROM    @Products P
        INNER JOIN TP
            ON P.Id = TP.Id

SELECT * FROM @Products

预期:

Id   Name       Description
---------------------------
1    NewName2   NewDesc2

但是得到:

Id   Name       Description
---------------------------
1    NewName1   NewDesc1

请注意,我通过ORDER BY RowNumber进行排序意味着首先更新RowNumber1然后是第二个,依此类推。

2 个答案:

答案 0 :(得分:3)

如果有多个匹配项,则SQL Server不会指定要更新的内容。如果您希望更新最后一个(或第一个)值,则使用窗口函数来查找它:

WITH TP AS (
    SELECT t.*,
           ROW_NUMBER() OVER (PARRTITION BY ID ORDER BY RowNumber DESC) as seqnum
    FROM (SELECT TOP (100000) tp.*
          FROM @TempProducts ORDER BY RowNumber ASC
         ) t
)
UPDATE  P
   SET  Name = ISNULL(TP.Name,P.Name),
        Description = ISNULL(TP.Description,P.Description)
FROM    @Products P INNER JOIN
        TP
        ON P.Id = TP.Id AND seqnum = 1;

答案 1 :(得分:1)

  

指定FROM子句以提供条件时要小心   用于更新操作。 UPDATE语句的结果是   如果语句包含不是的FROM子句,则为undefined   以这样的方式指定,每个只有一个值可用   更新的列出现,即UPDATE语句是否   不确定。

我会这样做:

UPDATE P SET   Name = ISNULL(ca1.Name, P.Name), Description = ISNULL(ca2.Description, P.Description)
FROM @Products P
OUTER APPLY(SELECT TOP 1 Name FROM @TempProducts WHERE ID = p.ID AND Name IS NOT NULL ORDER BY RowNumber DESC) ca1
OUTER APPLY(SELECT TOP 1 Description FROM @TempProducts WHERE ID = p.ID AND Description IS NOT NULL ORDER BY RowNumber DESC) ca2