Tips para realizar UPSERTs o updates con insert en SQL Server

En muchas ocasiones, especialmente en procesos ETL o de carga de datos para un data warehouse, por ejemplo, interesa hacer en una sola sentencia o en un solo paso la comprobación de si un registro existe, y si existe actualizarlo, y si no insertarlo. A esta combinación se le ha apodado UPSERT, aunque en SQL existe una sentencia específica para hacerlo, que es MERGE.

 Merge SQL

 

Reúno en este post algunas soluciones sencillas para hacer, con SQL Server, INSERTS o UPDATES en función de la existencia o no de los registros entrantes. Cambiando un poco la sintaxis se puede hacer lo mismo en otros motores de base de datos, como Oracle, o MySQL.

 

UPSERT en SQL Server

La intrucción SQL que permite 'mezclar' datos de dos tablas en una es MERGE. Tiene la particularidad de que su sintaxis permite especificar una sentencia SQL para el caso de que el registro que se va a insertar ya exista (si hay coincidencia en los campos que se definan), y otra sentencia diferente en el caso de que no haya ningún registro en la tabla destino con coincidencia de valores en los campos especificados. Lo normal es definir un update en el caso de que el registro ya exista y un insert en el caso contrario.

 

Merge para actualizar/insertar un registro

Quedará más claro con este ejemplo de cómo Insertar o actualizar valores fijos para un registro en concreto, cosa que podría ser útil, en un entorno DWH for example, para insertar en una dimensión el registro ficticio correspondiente a id's no encontrados (o dummy):

MERGE Tabla_Destino WITH(HOLDLOCK) as target using (values ('valor1', 'valor2')) as source (campo1, campo2) on target.idregistro = 23 when matched then update set campo1_dest = source.campo1, campo2_dest = source.campo2 when not matched then insert ( idregistro, campo1_dest, campo2_dest) values ( 23, source.campo1, source.codempresa);

Si el registro con idregistro=23 existe, se actualizan los campos campo1_dest y campo2_dest con los valores 'valor1' y 'valor2', respectivamente.
Si no existe, se inserta un registro con idregistro=23, valor1_dest='valor1' y valor2_dest='valor2' 

 

Transacciones para actualizar/insertar un registro

Otra solución sencilla para insertar/actualizar un registro, pero utilizando transacciones en lugar de la instrucción MERGE sería la siguiente:

(Con un cursor y parámetros se puede implementar fácilmente para actualizar/insertar más registros)

BEGIN TRAN SELECT idRegistro FROM Tabla_Destino WHERE idRegistro=23 IF @@ROWCOUNT = 0 insert ( idregistro, campo1_dest, campo2_dest) values ( 23, ‘valor1’, ‘valor2’); COMMIT TRAN

Se hace un update de la tabla. Si no se ha actualizado es que no existe el registro, y entonces se hace un insert. 

 

Merge para actualizar/insertar varios registros

El merge anterior insertaba un sólo registro, pero MERGE sirve para tomar como origen de datos tablas completas, o simplemente registros resultado de cualquier sentencia de selección (SELECT), con lo que podemos crear sentencias más potentes, para ejecutar eficientes operaciones que trabajan a nivel de conjunto, y que normalmente van a ser más rápidas que opciones como la transacción anterior.

Por ejemplo, para Insertar o actualizar valores que provengan de una tabla o vista:

MERGE Tabla_Destino WITH(HOLDLOCK) as target using (select idregistro, campo1, campo2 from Tabla_Origen) as source (campo1, campo2) on (target.idregistro = source.idregistro) when matched then update set campo1_dest = source.campo1, campo2_dest = source.campo2 when not matched then insert ( idregistro, campo1, campo2) values ( source.idregistro, source.campo1, source.campo2);

 

Referencias

Finalizo enlazando algunas referencias para el que quiera ampliar información:

 

 

Por Carlos Fernández

 

Si te ha gustado este post compártelo. Con el botón de 'SHARE' son sólo unos segundos.