SQL MERGE语句来更新数据
我有一个名为energydata
数据表
它只有三列
(webmeterID, DateTime, kWh)
我在表temp_energydata
新的更新数据。
DateTime
和webmeterID
保持不变。 但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
语句的并发问题 。 这很大程度上可以通过指定HOLDLOCK
或SERIALIZABLE
锁提示来解决:
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