Оператор SQL MERGE для обновления данных
У меня есть таблица с данными с именем energydata
он имеет всего три столбца
(webmeterID, DateTime, kWh)
У меня есть новый набор обновленных данных в таблице temp_energydata
.
- T-SQL Pivot? Возможность создания столбцов таблицы из значений строк
- Точность десятичного деления T-SQL
- Как искать одно значение в любом столбце любой таблицы внутри одной базы данных MS-SQL?
- Расстояние Левенштейна в T-SQL
- Результаты запроса T-SQL по результатам запроса
DateTime
и webmeterID
остаются неизменными. Но значения kWh
нуждаются в обновлении из таблицы temp_energydata
.
Как мне правильно написать T-SQL?
- Проверьте, является ли varchar числом (TSQL)
- Можно ли установить начало недели для функции T-SQL DATEDIFF?
- T-SQL: выбор строк для удаления с помощью соединений
- Как проверить, существует ли столбец в таблице SQL Server?
- Совокупная функция SQL для захвата только первой из каждой группы
- Как сделать SQL как% в Linq?
- Кодировка Base64 в SQL Server 2005 T-SQL
- Как преобразовать строку dd / mm / yyyy в datetime в SQL Server?
Предполагая, что вы хотите иметь фактическое заявление 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;
Поскольку это стало немного более популярным, мне кажется, что я должен немного расширить этот ответ с некоторыми оговорками, о которых нужно знать.
Во-первых, есть несколько блогов, которые сообщают о проблемах параллелизма с оператором MERGE
в более старых версиях SQL Server. Я не знаю, был ли этот вопрос когда-либо рассмотрен в последующих выпусках. В любом случае это можно в значительной степени решить, указав HOLDLOCK
блокировки HOLDLOCK
или SERIALIZABLE
:
MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target [...]
Вы также можете выполнить одно и то же с более строгими уровнями изоляции транзакций.
Есть несколько других известных проблем с MERGE
. (Обратите внимание, что поскольку Microsoft nuked Connect и не связала проблемы в старой системе с проблемами в новой системе, эти старые проблемы трудно отследить. Спасибо, Microsoft!) Из того, что я могу сказать, большинство из них не являются обычными проблемы или могут работать с такими же подсказками, как указано выше, но я их не тестировал.
Как бы то ни было, хотя у меня никогда не было никаких проблем с утверждением WITH (HOLDLOCK)
, я всегда использую подсказку 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_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.
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