72

我有一个名为的数据表energydata

它只有三列

(webmeterID, DateTime, kWh)

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

DateTime保持webmeterID不变。但是这些kWh值需要从temp_energydata表中更新。

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

4

6 回答 6

140

假设您想要一个实际的SQL ServerMERGE语句:

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 中语句的并发问题。MERGE我不知道这个问题是否在以后的版本中得到解决。无论哪种方式,这都可以通过指定HOLDLOCKorSERIALIZABLE锁定提示来解决:

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

您还可以使用更严格的事务隔离级别来完成同样的事情。

几个其他已知问题MERGE。(请注意,由于 Microsoft 核对 Connect 并且没有将旧系统中的问题与新系统中的问题联系起来,因此这些旧问题很难追查。谢谢,Microsoft!)据我所知,它们中的大多数并不常见问题或可以使用与上述相同的锁定提示来解决,但我还没有测试过它们。

事实上,即使我自己从未对MERGE语句有任何问题,但我现在总是使用WITH (HOLDLOCK)提示,并且我更喜欢仅在最直接的情况下使用该语句。

于 2013-02-11T06:25:55.350 回答
14

我经常使用 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
于 2016-09-05T21:02:38.990 回答
7

如果您只需要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一个语句中,那么您绝对应该使用 Bacon Bits 给出的答案。

于 2013-02-11T06:11:16.037 回答
0
UPDATE ed
SET ed.kWh = ted.kWh
FROM energydata ed
INNER JOIN temp_energydata ted ON ted.webmeterID = ed.webmeterID
于 2013-02-11T06:11:38.450 回答
0
Update energydata set energydata.kWh = temp.kWh 
where energydata.webmeterID = (select webmeterID from temp_energydata as temp) 
于 2013-02-11T06:16:37.373 回答
-7

正确的方法是:

UPDATE test1
INNER JOIN test2 ON (test1.id = test2.id)
SET test1.data = test2.data
于 2014-05-05T09:12:20.683 回答