Instrucción SQL MERGE para actualizar datos

Tengo una tabla con datos llamados energydata

tiene solo tres columnas

 (webmeterID, DateTime, kWh) 

Tengo un nuevo conjunto de datos actualizados en una tabla temp_energydata .

El DateTime y el webmeterID permanecen igual. Pero los valores de kWh deben actualizarse desde la tabla temp_energydata .

¿Cómo escribo el T-SQL para esto de la manera correcta?

Suponiendo que desea una statement MERGE real de SQL Server :

 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); 

Si también desea eliminar registros en el destino que no están en la fuente:

 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; 

Debido a que esto se ha vuelto un poco más popular, siento que debería ampliar esta respuesta un poco con algunas advertencias para tener en cuenta.

En primer lugar, hay varios blogs que informan problemas de concurrencia con la instrucción MERGE en versiones anteriores de SQL Server. No sé si alguna vez se ha tratado este problema en ediciones posteriores. De cualquier forma, esto puede HOLDLOCK especificando la SERIALIZABLE locking HOLDLOCK o SERIALIZABLE :

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

También puede lograr lo mismo con niveles de aislamiento de transacción más restrictivos.

Hay varios otros problemas conocidos con MERGE . (Tenga en cuenta que dado que Microsoft desconectó Connect y no vinculó problemas en el sistema anterior con problemas en el nuevo sistema, estos problemas más antiguos son difíciles de rastrear. ¡Gracias, Microsoft!) Por lo que puedo decir, la mayoría de ellos no son comunes problemas o se puede solucionar con los mismos consejos de locking que los anteriores, pero no los he probado.

Tal como están las cosas, aunque nunca he tenido ningún problema con la statement MERGE , siempre uso la sugerencia WITH (HOLDLOCK) ahora, y prefiero usar la statement solo en los casos más sencillos.

A menudo uso la gran respuesta de Bacon Bits ya que no puedo memorizar la syntax.

Pero generalmente agrego un CTE como una adición para hacer que la parte DELETE sea más útil porque muy a menudo querrás aplicar la fusión solo a una parte de la tabla de destino.

 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 

Si solo necesita actualizar sus registros en datos de energydata basados ​​en datos en temp_energydata , suponiendo que temp_enerydata no contiene ningún registro nuevo, intente esto:

 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 

Aquí está trabajando sqlfiddle

Pero si temp_energydata contiene nuevos registros y necesitas insertarlos en datos energydata preferencia con una statement, entonces definitivamente deberías ir con la respuesta que dio Bits Bacon.

 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) 

LA FORMA CORRECTA ES:

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