代码之家  ›  专栏  ›  技术社区  ›  Malick

如何通过仅更新TSQL中的空值来合并两行?

  •  0
  • Malick  · 技术社区  · 7 年前

    我希望合并两行数据,方法是基于其ID保留一行,并且仅在数据为空值时更新数据。

    例如,我想“合并”第1行和第2行并删除第2行:

    ID          date          col1          col2          col3       
    --------------------------------------------------------------- 
    1          31/12/2017       1           NULL          1
    2          31/12/2015       3           2             NULL            
    3          31/12/2014       4           5             NULL
    

    致:

    ID          date          col1          col2          col3       
    --------------------------------------------------------------- 
    1          31/12/2017       1           2             1
    3          31/12/2014       4           5             NULL
    

        UPDATE MyTable
    SET
       date = newdata.date
       FROM
        (
        SELECT
           date
        FROM  MyTable 
            WHERE
                ID =  2     
        ) 
        newdata
    WHERE
         ID =  1 AND   MyTable.date IS NULL ;
    

    我希望在非常大的表上执行相同的操作,因此我正在寻找一种方法,将上述操作自动应用于两个特定行的表的每一列(或更好的解决方法?)。 要清楚,列名称( date

    该表有许多行,但我只想合并两行(这将始终是两行)

    1 回复  |  直到 7 年前
        1
  •  3
  •   Thom A    7 年前

    我现在发布了一个答案,因为OP的评论似乎确实推断出这真的和我认为的一样简单。虽然他们的表有很多行,但他们只对更正/合并行1和2的值感兴趣。因为这些行过于简单,所以您可以 UPDATE ID 1的值,然后 DELETE 第2排。

    因为只有少数几列,所以您可以简单地使用文本值,因为我们可以直观地看到这一点 Col2 需要更新ID 1上的:

    UPDATE YourTable
    SET col2 = 2
    WHERE ID = 1;
    

    现在ID 1具有正确的值,您可以 删除 ID 2:

    DELETE
    FROM YourTable
    WHERE ID = 2;
    

    但是,如果您认为数据(有点)过于简化,您可以执行以下操作。

    UPDATE YT1
    SET Col1 = ISNULL(YT1.Col1,YT2.Col1),
        Col2 = ISNULL(YT1.Col2,YT2.Col2),
        Col3 = ISNULL(YT1.Col3,YT2.Col3),
        ...
    FROM YourTable YT1
         JOIN YourTable YT2 ON YT2.ID = 2
    WHERE YT1.ID = 1;
    
    DELETE
    FROM YourTable
    WHERE ID = 2;
    

    一些 更多(但不够)细节。这是一个可伸缩的动态SQL解决方案,因为它写出了 ISNULL

    CREATE TABLE YourTable (ID int,
                            [date] date,
                            col1 int,
                            col2 int,
                            col3 int,
                            col4 int,
                            col5 int);
    
    GO
    
    INSERT INTO YourTable
    VALUES (1,'20171231',1,NULL,1   ,2   ,NULL),
           (2,'20151231',3,2   ,NULL,NULL,4),            
           (3,'20141231',4,5   ,NULL,2   ,7);
    
    SELECT *
    FROM YourTable;
    
    GO
    
    DECLARE @SQL nvarchar(MAX);
    DECLARE @TableName sysname = N'YourTable'
    DECLARE @CopyToId int = 1;
    DECLARE @DeleteID int = 2;
    
    SET @SQL = N'UPDATE YT1' + NCHAR(10) +
               N'SET ' + STUFF((SELECT N',' + NCHAR(10) +
                                       N'    ' + QUOTENAME(c.[name]) + N' = ISNULL(YT1.' + QUOTENAME(c.[name]) + N',YT2.' + QUOTENAME(c.[name]) + N')'
                                FROM sys.tables t
                                     JOIN sys.columns c ON t.[object_id] = c.[object_id]
                                WHERE t.[name] = @TableName
                                  AND c.name NOT IN (N'ID',N'date')
                                FOR XML PATH(N'')),1,6,N'') + NCHAR(10) +
              N'FROM ' + QUOTENAME(@TableName) + N' YT1' + NCHAR(10) +
              N'     JOIN ' + QUOTENAME(@TableName) + N' YT2 ON YT2.ID = @dDeleteID' + NCHAR(10) +
              N'WHERE YT1.ID = @dCopyToId;' + NCHAR(10) + NCHAR(10) +
              N'DELETE' + NCHAR(10) +
              N'FROM ' + QUOTENAME(@TableName) + NCHAR(10) +
              N'WHERE ID = @dDeleteID;';
    
    PRINT @SQL; --Your Best friend
    
    EXEC sp_executesql @SQL, N'@dCopyToID int, @dDeleteID int', @dCopyToId = @CopyToId, @dDeleteID = @DeleteID;
    
    GO
    SELECT *
    FROM YourTable;
    GO
    DROP TABLE YourTable;