Que es lo que se hace cuando en una aplicación requerimos agregar un registro nuevo, pero si este ya existe modificarlo con los nuevos datos. Si estas utilizando SQL Server 2005 o inferior debes escribir 2 o 3 querys, uno para verificar si el registro existe, si existe entonces actualizas y si no existe lo insertas. En SQL Server 2008 se han hecho cambios para mejorar esto y ahora en una sola sentencia puedes hacer esto, insert o update usando la instrucción MERGE.
La instrucción MERGE básicamente une datos de un resultado de origen establecido en una tabla destino. Se envían los datos al MERGE, el los compara (por la llave primaria), si existe los actualiza y si no existe los ingresa, también podría ser que si no cumple con los requisitos los pueda borrar, insert, update y delete en una sola instrucción.
MERGE también permite comparar dos tablas, una fuente y otra destino en ingresar o modificar los datos de la tabla en base a los datos de otra tabla, eso lo veremos en otro ejemplo que publicaremos en este sitio.
En este primer ejemplo sobre MERGE vamos a hacer el manejo típico de datos en una tabla, insert y update.
Tabla que vamos a utilizar de ejemplo.
CREATE TABLE [dbo].[tablaPrueba]( [id] [int] NOT NULL, [nombre] [varchar](50) NULL, [fecha_ingreso] [datetime] NULL, [fecha_actualizacion] [datetime] NULL, CONSTRAINT [PK_tablaPrueba] PRIMARY KEY CLUSTERED ( [id] ASC )
Primero vamos a mostrar como se hace o hacia normalmente en SQL, principalmente si se utiliza SQL 2005 o inferior.
-- Ejemplo 1 obsoleto pero funcional en SQL 2008 o superior CREATE PROCEDURE InsertaTablaPrueba( @id int, @nombre varchar(50) ) AS BEGIN SET NOCOUNT ON --Se actualizan los registros en la tabla UPDATE tablaPrueba SET nombre = @nombre, fecha_actualizacion = GETDATE() WHERE id = @id --Si no se actualizó ningún registro se inserta en la tabla IF (@@ROWCOUNT = 0 ) BEGIN INSERT INTO tablaPrueba (id, nombre, fecha_ingreso, fecha_actualizacion) VALUES(@id, @nombre, GETDATE(), GETDATE()) END END
En ese ejemplo podemos ver que se solicitar modificar un registro y si este no afectó ningún registro (@@ROWCOUNT=0) lo actualiza. En el peor de los casos se ejecutan dos querys, se toca dos veces la tabla.
-- Ejemplo 2, obsoleto pero funcional en SQL 2008 o superior CREATE PROCEDURE InsertaTablaPrueba2( @id int, @nombre varchar(50) ) AS BEGIN SET NOCOUNT ON IF EXISTS(SELECT 1 FROM tablaPrueba WHERE id = @id) BEGIN --Se actualizan los registros en la tabla UPDATE tablaPrueba SET nombre = @nombre, fecha_actualizacion = GETDATE() WHERE id = @id END ELSE BEGIN --Si no existe el registro se inserta en la tabla INSERT INTO tablaPrueba (id, nombre, fecha_ingreso, fecha_actualizacion) VALUES(@id, @nombre, GETDATE(), GETDATE()) END END
En este ejemplo se consulta si el registro existe, y luego se actualiza o se inserta, siempre se toca 2 veces la tabla.
Ahora en el siguiente ejemplo vamos a utilizar MERGE, vamos a ver como en una sola sentencia se inserta o actualiza un registro, mucho más eficiente.
-- Ejemplo 3, usando MERGE, mucho más eficiente CREATE PROCEDURE InsertaTablaPruebaMerge( @id int, @nombre varchar(50) ) AS BEGIN SET NOCOUNT ON MERGE tablaPrueba as TARGET USING(SELECT @id, @nombre) AS SOURCE(id, nombre) ON (TARGET.id = SOURCE.id) WHEN MATCHED THEN UPDATE SET nombre = SOURCE.nombre, fecha_actualizacion = GETDATE() WHEN NOT MATCHED THEN INSERT (id, nombre, fecha_ingreso, fecha_actualizacion) VALUES (SOURCE.id, SOURCE.nombre, GETDATE(), GETDATE()); END
Podemos ver que MERGE recibe una tabla destino, que es a la que se le van a ingresar o modificar los datos (TARGET), luego recibe la tabla fuente o los datos fuente, en este caso son datos fuente (SOURCE). Luego de estos, cuando los datos concuerdan (WHEN MATCHED) realiza el UPDATE en la tabla, y cuando no existen los registros (WHEN NOT MATCHED) realiza el INSERT
Datos para probar los 3 procedimientos
EXEC InsertaTablaPrueba 1, 'Valor núm. 1' EXEC InsertaTablaPrueba 2, 'Valor núm. 2' EXEC InsertaTablaPrueba 3, 'Valor núm. 3' EXEC InsertaTablaPrueba 4, 'Valor núm. 4' EXEC InsertaTablaPrueba2 4, 'Valor núm. 4.1' EXEC InsertaTablaPruebaMerge 5, 'Valor núm. 5' EXEC InsertaTablaPruebaMerge 3, 'Valor núm. 3.1' EXEC InsertaTablaPruebaMerge 6, 'Valor núm. 6' EXEC InsertaTablaPrueba 2, 'Valor núm. 2.1' SELECT * FROM tablaPrueba