SQL MERGE语句来更新数据

我有一个名为energydata数据表

它只有三列

 (webmeterID, DateTime, kWh) 

我在表temp_energydata新的更新数据。

DateTimewebmeterID保持不变。 但kWh值需要从temp_energydata表更新。

我如何以正确的方式编写T-SQL?

假设你想要一个实际的SQL Server MERGE语句:

 MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target USING dbo.temp_energydata AS source ON target.webmeterID = source.webmeterID AND target.DateTime = source.DateTime WHEN MATCHED THEN UPDATE SET target.kWh = source.kWh WHEN NOT MATCHED BY TARGET THEN INSERT (webmeterID, DateTime, kWh) VALUES (source.webmeterID, source.DateTime, source.kWh); 

如果您还想删除目标中不在源代码中的logging,请执行以下操作:

 MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target USING dbo.temp_energydata AS source ON target.webmeterID = source.webmeterID AND target.DateTime = source.DateTime WHEN MATCHED THEN UPDATE SET target.kWh = source.kWh WHEN NOT MATCHED BY TARGET THEN INSERT (webmeterID, DateTime, kWh) VALUES (source.webmeterID, source.DateTime, source.kWh) WHEN NOT MATCHED BY SOURCE THEN DELETE; 

因为这已经变得越来越stream行了,所以我觉得我应该扩大这个答案,有一些注意事项要注意。

首先,有几个博客报告了MERGE语句的并发问题 。 这很大程度上可以通过指定HOLDLOCKSERIALIZABLE锁提示来解决:

 MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target [...] 

你也可以用更严格的事务隔离级别完成同样的事情。

MERGE还有其他几个已知的问题 。 从我所知道的来看,其中大部分都不是常见的问题,或者可以用上面的locking提示来解决,但是我没有对它们进行testing。

事实上,即使我自己从来没有遇到任何MERGE语句问题,我现在总是使用WITH (HOLDLOCK)提示,而且我只希望在最直接的情况下使用该语句。

我经常使用Bacon Bits,因为我无法记住语法。

但是我通常添加一个CTE作为一个附加,使DELETE部分更有用,因为很多时候你只想将合并应用到目标表的一部分。

 WITH target as ( SELECT * FROM dbo.energydate WHERE DateTime > GETDATE() ) MERGE INTO target WITH (HOLDLOCK) USING dbo.temp_energydata AS source ON target.webmeterID = source.webmeterID AND target.DateTime = source.DateTime WHEN MATCHED THEN UPDATE SET target.kWh = source.kWh WHEN NOT MATCHED BY TARGET THEN INSERT (webmeterID, DateTime, kWh) VALUES (source.webmeterID, source.DateTime, source.kWh) WHEN NOT MATCHED BY SOURCE THEN DELETE 

如果您只需要根据energydata的数据更新temp_enerydata中的logging,则假定temp_enerydata不包含任何新logging,请尝试以下操作:

 UPDATE e SET e.kWh = t.kWh FROM energydata e INNER JOIN temp_energydata t ON e.webmeterID = t.webmeterID AND e.DateTime = t.DateTime 

这里是工作sqlfiddle

但是,如果temp_energydata包含新的logging,你需要插入到energydata最好有一个声明,那么你一定要去与培根位给的答案。

 UPDATE ed SET ed.kWh = ted.kWh FROM energydata ed INNER JOIN temp_energydata ted ON ted.webmeterID = ed.webmeterID 
 Update energydata set energydata.kWh = temp.kWh where energydata.webmeterID = (select webmeterID from temp_energydata as temp) 

正确的方法是:

 UPDATE test1 INNER JOIN test2 ON (test1.id = test2.id) SET test1.data = test2.data