Подтвердить что ты не робот

Оператор SQL MERGE для обновления данных

У меня есть таблица с данными с именем energydata

он имеет всего три столбца

(webmeterID, DateTime, kWh)

У меня есть новый набор обновленных данных в таблице temp_energydata.

DateTime и webmeterID остаются неизменными. Но значения kWh нуждаются в обновлении из таблицы temp_energydata.

Как мне правильно написать T-SQL?

4b9b3361

Ответ 1

Предполагая, что вам нужен фактический 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;

Поскольку это стало немного более популярным, мне кажется, что я должен немного расширить этот ответ с некоторыми оговорками, о которых нужно знать.

Во-первых, есть несколько блогов, которые сообщают о проблемах concurrency с инструкцией MERGE. В основном это можно обойти, указав подсказку HOLDLOCK или SERIALIZABLE:

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

Вы также можете выполнить одно и то же с более строгими уровнями изоляции транзакций.

Есть несколько других известных проблем с MERGE. Из того, что я могу сказать, большинство из них не являются общими проблемами или могут работать с такими же подсказками, как указано выше, но я их не тестировал.

Как бы то ни было, хотя у меня никогда не было никаких проблем с выражением MERGE, я всегда использую подсказку WITH (HOLDLOCK) сейчас, и я предпочитаю использовать этот оператор только в самых простых случаях.

Ответ 2

Я часто использовал 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

Ответ 3

Если вам нужно просто обновить свои записи в 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.

Ответ 4

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

Ответ 5

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

Ответ 6

ПРАВИЛЬНЫЙ ПУТЬ:

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