Sql server 仅当行与当前值不同时更新/插入行

Sql server 仅当行与当前值不同时更新/插入行,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我有一个桌面应用程序,它将包含产品信息的数据表发送到SQL Server db。我只想更新与接收行不同的列的表。我想知道什么是正确的方式: 检查接收到的数据表中的值是否与实际db表中的值不同,如果是,则更新该表 如果修改了该值,则在包含日志的表中插入新行 我目前的工作: 我从新变量@OldValue内的数据表中选择当前值,然后将其与接收到的值@NewValue进行比较。如果值不同,我只需更新列并在日志表中插入一条新记录 DECLARE @ProductId = 333 IF @OldValue

我有一个桌面应用程序,它将包含产品信息的数据表发送到SQL Server db。我只想更新与接收行不同的列的表。我想知道什么是正确的方式:

检查接收到的数据表中的值是否与实际db表中的值不同,如果是,则更新该表 如果修改了该值,则在包含日志的表中插入新行 我目前的工作:

我从新变量@OldValue内的数据表中选择当前值,然后将其与接收到的值@NewValue进行比较。如果值不同,我只需更新列并在日志表中插入一条新记录

DECLARE @ProductId = 333
IF @OldValue <> @NewValue
BEGIN
    UPDATE dbo.ProductTable
       SET Column1 = @NewValue
    WHERE
       ProductId = @ProductId




 INSERT INTO 
     dbo.Logs
 VALUES
     (@ProductId, @ModifiedColumn, @OldValue, @NewValue, GETDATE())

END
如果数据发生更改,我会对每个需要更新的列进行检查,但是接收到的数据表包含大约15列,我认为必须有一个更优雅的解决方案来解决这个问题


任何有用的提示都将不胜感激。

我经常看到这种问题。在大多数情况下,我们连接所有列,由一个固定字符串(如“| |”)分隔,然后对两个表应用HASHBYTES'MD5',MyConcatenatedValue函数。如果哈希相同,则不更新该行。如果不一样,我们会更新它

如果我重用您的代码,它可能会是这样的:

DECLARE @ProductId = 333
SET @OldValue =     SELECT(HASHBYTES('MD5',Column1+'||'+Column2+'||'+Column3+'||'+Column4+'||'+Column5+'||'+Column6) FROM dbo.ProductTable) -- continue this logic for each column
SET @NewValue =     SELECT(HASHBYTES('MD5',Column1+'||'+Column2+'||'+Column3+'||'+Column4+'||'+Column5+'||'+Column6) FROM dbo.SourceTable) -- I assume you have a table with new values stored
IF @OldValue <> @NewValue
BEGIN
    UPDATE Product 
    FROM dbo.ProductTable Product
    INNER JOIN dbo.SourceTable Source 
       ON Product.ProductId = Source.ProductId
       SET Product.Column1 = Source.Column1
          ,Product.Column2 = Source.Column2
          ,Product.Column3 = Source.Column3
          ,Product.Column4 = Source.Column4
          ,Product.Column5 = Source.Column5
          ,Product.Column6 = Source.Column6              
    WHERE
      ProductId = @ProductId
END
但是,您无法轻松地将其中一列记录为已被替换,因为您对所有列进行了一次检查。也许你应该考虑实现时态表。以下是一篇关于它的文章:


我希望这能有所帮助,如果您需要更多详细信息,请告诉我。

我可能会做如下操作。这目前只满足两个列的需求,但应该清楚如何在中添加其他列

DECLARE @UpdateResult TABLE
(
ProductId INT PRIMARY KEY,
dCol1 VARCHAR(50), /*These should be whatever the datatype of the relevant columns in dbo.Logs are*/
iCol1 VARCHAR(50), 
dCol2 VARCHAR(50), 
iCol2 VARCHAR(50)
);


UPDATE PT
SET PT.Col1 = Tvp.Col1, 
    PT.Col2 = Tvp.Col2 
    OUTPUT inserted.ProductId, 
           deleted.Col1, 
           inserted.Col1 ,
           deleted.Col2, 
           inserted.Col2 INTO @UpdateResult(ProductId, dCol1, iCol1, dCol2,iCol2 )
FROM dbo.ProductTable AS PT
JOIN @Tvp Tvp ON Tvp.ProductId = PT.ProductId
/*Only update where at least one column is different*/
WHERE EXISTS (SELECT PT.Col1, PT.Col2 
              EXCEPT 
              SELECT Tvp.Col1, Tvp.Col2)


INSERT INTO dbo.Logs
SELECT ProductId, ModifiedColumn, OldValue, NewValue, getdate()
FROM @UpdateResult
CROSS APPLY (VALUES
                    ('Col1',dCol1, iCol1),
                    ('Col2',dCol2, iCol2)
            ) unpvt(ModifiedColumn, OldValue, NewValue )
WHERE EXISTS (SELECT OldValue EXCEPT SELECT NewValue)

您的表中是否只有一列正在更新?日志表和更新意味着只更新列;是否正确?否,目标表和源表都包含15列,其中包含ProductId、ProductName、ProductPrice等数据@LarNu您使用的是哪个版本的SQL Server?@ZoharPeled 2012是否可以对客户端执行任何预处理?仅发回已更改的行。您可以使用触发器来更新日志文件,而不是单独的脚本。见解深刻,但遗憾的是没有回答问题:我可能误解了,但您想知道一个优雅的解决方案来检查是否需要更新包含15+列的行。我刚刚给了你分析领域的最佳实践。我很想知道关于你的问题我遗漏了什么。你直接需要代码吗?我没有问这个问题-我只是想帮助一个新用户了解为什么没有UPVOLUES:是的,我想至少举一个例子,说明如何使用实际的SQL代码来实现这一点会很有用。你概述了一个策略,而不是一个解决方案。好吧,我现在更明白了。我试图根据一些推测添加一个具体的例子。感谢您的帮助和反馈:-是的,现在从meI获得a+1。我将查看您的解决方案,稍后让您知道,谢谢;这就行了。谢谢~!