Tips para realizar UPSETs 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 UPSET, 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.

 

UPSET 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:

 

 

 excelente aporte.. muy facil

 excelente aporte.. muy facil de enteder ...gracias sigan asi

Gracias a ti por el interés,

Gracias a ti por el interés, la intención es que sea útil.

Saludos,

Contenido relacionado

  • El error ORA-30926 suele producirse cuando se realizan operaciones Merge, y lo normal es que nos deje algo descolocados, ya que la descripción del mismo no da demasiada información sobre lo que está pasando:
    ORA-30926: unable to get a stable set of rows in the source tables.

    Normalmente este error se produce cuando en la operación Merge a una fila destino que hay que actualizar le corresponden más de una fila en la tabla origen. Como el motor no sabe qué registro escoger devuelve un error. Es un problema de duplicidad en la tabla origen...

  • Cuando uno de nuestros mappings realiza una carga sobre una tabla en modo INSERT/UPDATE puede que nuestro proceso falle devolviendo este extraño error:
    ORA-30926: no se ha podido obtener un juego de filas estable en las tablas de origen

    La explicación suele ser que al final este tipo de cargas realiza una operación de MERGE, y si en la correspondencia entre los datos origen y los datos destino a un registro de la tabla destino le toca más de uno de las tablas origen el MERGE no funciona y devuelve este error. Normalmente se trata de un problema de duplicidad en los registros origen.

    Para ver una explicación más extensa y las opciones para solucionarlo, consultar El error ORA-30926 como resultado de una operación Merge

  • Para importar y exportar datos de SQL Server Microsoft proporciona la herramienta bpc, que funciona por linea de comandos. Aunque sería de agradecer que SQL Server Management Studio proporcionara alguna utilidad gráfica de importación/exportación que nos evitara tener que recurrir a utilizar la línea de comandos, bpc es muy fácil de utilizar, al menos para hacer cosas sencillas. También es de los métodos más eficientes para exportar o importar datos en SQL Server.

    La sintaxis básica de este comando es esta:

    bcp {tabla o consulta} {in/out} nombre_del_fichero [opciones]

    Las opciones se pueden complicar bastante, e incluso se pueden construir y utilizar ficheros de formato, pero para la mayoría de los casos puede ser suficiente con utilizar las opciones más básicas que nos permitan utilizar un fichero para exportar/importar los datos de una tabla:

  • Buenas soy nuevo con oracle, estoy optimizando algunas consultas por lo cual realizo creacion de vistas, tablas, store procedures y jobs

     

    1- Create table tEmpleados (la tabla esta indexada)

    2- Create or Replace vEmpleados

    3-  CREATE OR REPLACE PROCEDURE ESQUEMA.LOAD_EMPLEADOS

         AS

         BEGIN

            EXECUTE IMMEDIATE 'TRUNCATE TABLE tEmpleados' ;

            INSERT INTO tEmpleados( campo1 , campo 2) SELECT campo1, campo2 FROM vEmpleados;

            COMMIT;

     

         END LOAD_EMPLEADOS;

    4- Genero JOBS

  • Muchas veces es necesario conocer el último id insertado en una columna identity (auto-numérica) o también la última o últimas filas insertadas en una tabla.

    Muchos desarrolladores tratan esto con algunas prácticas que no son muy buenas, algunos ejemplos pueden ser ejecutar una consulta del estilo SELECT MAX(id) FROM tabla luego de insertar, SELECT * FROM tabla WHERE descripcion='algún dato unique que se tenía antes de insertar' o almacenar últimos valores de clave en una tabla.

    DB2 posee una serie de características que permiten lidiar con estos problemas y darles una solución sencilla y elegante, además se tendrá en cuenta la concurrencia y la eficiencia en la ejecución.
     

     

 

 

 

Gestion del Conocimiento    |    Business Intelligence y Analítica    |     Bases de Datos    |      ERP     |      CRM      |     Tendencias tecnológicas