用于更新数据的 SQLMERGE 语句

我有一个数据表,名为 energydata

只有三根柱子

(webmeterID, DateTime, kWh)

我有一套新的更新数据在一个表 temp_energydata

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

我如何正确地编写这个 T-SQL?

116942 次浏览

如果您只需要根据 temp_energydata中的数据更新 energydata中的记录,假设 temp_enerydata中不包含任何新记录,那么可以尝试这样做:

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包含新的记录,您需要插入到 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)

假设您想要一个实际的 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);

如果还想删除目标中不在源中的记录:

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;

因为这已经变得更加流行,我觉得我应该扩展这个问题的答案,并提出一些需要注意的问题。

首先,有几个博客在旧版本的 SQLServer 中报告 MERGE语句的并发性问题。我不知道这个问题是否曾经在以后的版本中得到解决。无论哪种方式,这都可以通过指定 HOLDLOCKSERIALIZABLE锁提示来解决:

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

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

还有其他一些已知的问题MERGE。(注意,由于微软对 Connect 进行了核攻击,并且没有将旧系统中的问题与新系统中的问题联系起来,因此很难追踪到这些旧问题。谢谢,微软!)据我所知,它们中的大多数都不是常见问题,或者可以使用与上面相同的锁提示来解决,但是我还没有对它们进行测试。

实际上,尽管我自己从来没有遇到过 MERGE语句的任何问题,但是我现在总是使用 WITH (HOLDLOCK)提示,而且我更喜欢只在最简单的情况下使用该语句。

正确的方法是:

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

我经常使用培根位伟大的答案,因为我只是不能记住语法。

但是我通常会添加一个 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