用于更新数据的SQL MERGE语句

时间:2013-02-11 06:06:10

标签: sql-server-2008 tsql

我有一个名为energydata

的数据表

它只有三列

(webmeterID, DateTime, kWh)

我在表temp_energydata中有一组新的更新数据。

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

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

6 个答案:

答案 0 :(得分:114)

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

因为这已经变得更受欢迎,我觉得我应该稍微扩展这个答案,并注意一些注意事项。

首先,有几个博客在旧版本的SQL Server中报告concurrency issues with the MERGE statement。我不知道这个问题是否曾在以后的版本中得到解决。无论哪种方式,通过指定HOLDLOCKSERIALIZABLE锁定提示,可以在很大程度上解决这个问题:

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

您还可以使用更具限制性的事务隔离级别来完成相同的操作。

several other known issuesMERGE。 (请注意,由于微软认为Connect并没有将旧系统中的问题与新系统中的问题联系起来,因此很难追查这些旧问题。谢谢,微软!)据我所知,其中大多数都不常见问题或可以使用与上面相同的锁定提示解决,但我没有测试它们。

实际上,即使我自己从未对MERGE语句有任何问题,我现在总是使用WITH (HOLDLOCK)提示,而我更喜欢只使用最直接的语句案件。

答案 1 :(得分:13)

我经常使用培根比特很好的答案,因为我无法记住语法。

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

答案 2 :(得分:5)

如果您需要根据energydata中的数据更新temp_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,最好只有一个陈述,那么您一定应该接受培根比特给出的答案。

答案 3 :(得分:0)

UPDATE ed
SET ed.kWh = ted.kWh
FROM energydata ed
INNER JOIN temp_energydata ted ON ted.webmeterID = ed.webmeterID

答案 4 :(得分:0)

Update energydata set energydata.kWh = temp.kWh 
where energydata.webmeterID = (select webmeterID from temp_energydata as temp) 

答案 5 :(得分:-7)

正确的方法是:

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