首页 > 解决方案 > 如何通过仅更新 TSQL 中的 NULL 值来合并两行?

问题描述

我想合并两行数据,方法是根据其 ID 保留一行,并且仅在数据为 NULL 值时才更新数据。

例如,我想“合并”第 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

在示例中,我想保留第 1 行,并用第 2 行中的值填充第 1 行中的 NULL 值。然后我将删除第 2 行。请参见下面我为日期列制作的代码。

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

我想在非常大的表上执行相同的操作,所以我正在寻找一种方法来自动将上述操作(或更好的解决方法?)应用于两个特定行的表的每一列。需要明确的是,列名 ( date) 不应该像上面的例子那样被硬编码,因为我有很多不同的表。

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

你能帮我解决这个问题吗?

标签: sql-servertsql

解决方案


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

由于只有几列,因此您可以简单地使用文字值,因为我们可以直观地看到只有Col2ID 1 需要更新:

UPDATE YourTable
SET col2 = 2
WHERE ID = 1;

现在 ID 1 有正确的值,你可以DELETEID 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;

这是基于 OP 问题下的所有评论,这些评论提供更多(但还不够)细节。这是一个可扩展的动态 SQL 解决方案,因为它为 OP 写出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;

推荐阅读