Sql server 仅当行与当前值不同时更新/插入行
我有一个桌面应用程序,它将包含产品信息的数据表发送到SQL Server db。我只想更新与接收行不同的列的表。我想知道什么是正确的方式: 检查接收到的数据表中的值是否与实际db表中的值不同,如果是,则更新该表 如果修改了该值,则在包含日志的表中插入新行 我目前的工作: 我从新变量@OldValue内的数据表中选择当前值,然后将其与接收到的值@NewValue进行比较。如果值不同,我只需更新列并在日志表中插入一条新记录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
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。我将查看您的解决方案,稍后让您知道,谢谢;这就行了。谢谢~!