2015/01/19

MERGE INTO

Tal vez algunos ya han utilizado esta sentencia, la ocupamos para insertar, actualizar o borrar filas de acuerdo a los resultados que se realizan de la combinación de una tabla con otro origen de datos, esta última puede ser un CTE, una variable tipo tabla, entre algunas otras.

La sintaxis sería la siguiente, recordemos que el código encerrado por corchetes es opcional:
MERGE INTO <tablaobjetivo> AS obj
USING <tablafuente> AS fuente
 ON <clausula coincidencia>
WHEN MATCHED [ AND < clausula >]
 THEN < codigo >
WHEN NOT MATCHED [BY TARGET] [AND < clausula >]
 THEN INSERT...
WHEN NOT MATCHED BY SOURCE [AND < clausula >]
 THEN <codigo>
[OUTPUT ...]
Ahora veamos para que sirve cada una:

MERGE INTO <tablaObjetivo>  : Define la tabla a la cual le realizaremos las operaciones INSERT, UPDATE, o DELETE.
USING <tablaFuente>: Define la tabla de la cual provienen los datos, aunque también se puede utilizar un CTE o tabla derivada entre algunas otras opciones. Lo más común es utilizar una tabla.
ON <clausula de coincidencia>: Define la cláusula utilizada para encontrar las coincidencias entre ambas tablas, fuente y destino, muy parecido al ON de un JOIN.
WHEN MATCHED [ AND <clausula>] THEN <codigo>: Se utiliza cuando existen coincidencias a través de la cláusula ON, por lo tanto la acción INSERT no está permitida; es posible utilizar 2 cláusulas WHEN MATCHED, una para utilizar la acción UPDATE y otra para la acción DELETE, la única condicionante es que deben tener filtros si se utilizan ambas,  esto se los explicaré con ejemplos posteriormente.
WHEN NOT MATCHED [BY TARGET] [AND <clausula>] THEN INSERT... Se utiliza cuando una fila existe en la fuente pero no en el destino, por lo tanto la única operación permitida es un INSERT.
WHEN NOT MATCHED BY SOURCE [AND < clausula >] THEN <codigo> Es el caso contrario a la cláusula anterior, cuando la fila existe en la tabla destino pero no en la fuente, no se puede aplicar una operación INSERT pero si UPDATE y DELETE, también se puede declarar dos cláusulas de este tipo al igual que la claúsula WHEN MATCHED, con la misma condicionante que deben tener filtros.
OUTPUT Se pueden obtener los datos insertados, eliminados y actualizados por medio de las palabras reservadas inserted y deleted, esto lo expliqué en otro en la publicación CLAUSULA OUTPUT( inserted, deleted ) SIN TRIGGERS.

Como nota importante, no es necesario declarar los 3 tipos de WHEN en nuestra sentencia, solo se requiere una como mínimo para ejecutarla. Ahora vamos a los ejemplos, los dos ejemplos hacen el mismo proceso, la diferencia radica en que uno utiliza CTE y el otro una variable tipo tabla:
Ejemplo usando CTE:
IF OBJECT_ID( 'dbo.prueba' ) IS NOT NULL
 DROP TABLE dbo.prueba 

CREATE TABLE dbo.prueba
(
 cve TINYINT
 , tipo CHAR(1)
 , edad SMALLINT
 , nombre VARCHAR(30)
 , CONSTRAINT pkPrueba PRIMARY KEY ( cve, tipo )
)
INSERT INTO dbo.prueba( cve,  tipo, edad, nombre )
VALUES( 1 , 'A' , 30 , 'PEDRO' )
, ( 2 , 'A' , 22 , 'IGNACIO' )
, ( 3 , 'B' , 23 , 'JUAN' )
, ( 4 , 'C' , 20, 'LUIS' )

;WITH cte AS(
 SELECT 2 AS cve, 'A' AS tipo, 28 AS edad, 'RAYMUNDO' AS nombre
 UNION
 SELECT 3,  'B' , 20 , 'SERGIO'
 UNION
 SELECT 4,  'D' , 29 , 'ALBERTO'
 UNION
 SELECT 5,  'A' , 29 , 'CARLOS'
)

MERGE INTO prueba AS obj
USING cte AS fuente
ON obj.cve = fuente.cve AND obj.tipo = fuente.tipo 
WHEN MATCHED AND obj.edad > fuente.edad 
 THEN UPDATE 
 SET obj.tipo = fuente.tipo , obj.edad = fuente.edad
  , obj.nombre = fuente.nombre
WHEN MATCHED AND obj.edad < fuente.edad 
 THEN DELETE
WHEN NOT MATCHED BY TARGET
 THEN INSERT VALUES( fuente.cve, fuente.tipo, fuente.edad, fuente.nombre )
WHEN NOT MATCHED BY SOURCE AND obj.edad <= 25 
 THEN DELETE
WHEN NOT MATCHED BY SOURCE AND obj.edad > 25 
 THEN UPDATE SET obj.nombre = 'MODIFICADO'
OUTPUT $action AS theAction, inserted.* , deleted.*
;

SELECT * FROM prueba;
Ejemplo usando variable tipo tabla:
IF OBJECT_ID( 'dbo.prueba' ) IS NOT NULL
 DROP TABLE dbo.prueba 

CREATE TABLE dbo.prueba
(
 cve TINYINT
 , tipo CHAR(1)
 , edad SMALLINT
 , nombre VARCHAR(30)
 , CONSTRAINT pkPrueba PRIMARY KEY ( cve, tipo )
)

INSERT INTO dbo.prueba( cve,  tipo, edad, nombre )
VALUES( 1 , 'A' , 30 , 'PEDRO' )
, ( 2 , 'A' , 22 , 'IGNACIO' )
, ( 3 , 'B' , 23 , 'JUAN' )
, ( 4 , 'C' , 20, 'LUIS' )

DECLARE @t TABLE ( cve TINYINT, tipo CHAR(1), edad SMALLINT, nombre VARCHAR(30) )

INSERT INTO @t
 SELECT 2 AS cve, 'A' AS tipo, 28 AS edad, 'RAYMUNDO' AS nombre
 UNION
 SELECT 3,  'B' , 20 , 'SERGIO'
 UNION
 SELECT 4,  'D' , 29 , 'ALBERTO'
 UNION
 SELECT 5,  'A' , 29 , 'CARLOS'

MERGE INTO prueba AS obj
USING @t AS fuente
ON obj.cve = fuente.cve AND obj.tipo = fuente.tipo 
WHEN MATCHED AND obj.edad > fuente.edad 
 THEN UPDATE 
 SET obj.tipo = fuente.tipo , obj.edad = fuente.edad
  , obj.nombre = fuente.nombre
WHEN MATCHED AND obj.edad < fuente.edad 
 THEN DELETE
WHEN NOT MATCHED BY TARGET
 THEN INSERT VALUES( fuente.cve, fuente.tipo, fuente.edad, fuente.nombre )
WHEN NOT MATCHED BY SOURCE AND obj.edad <= 25 
 THEN DELETE
WHEN NOT MATCHED BY SOURCE AND obj.edad > 25 
 THEN UPDATE SET obj.nombre = 'MODIFICADO'
OUTPUT $action AS theAction, inserted.* , deleted.*
;

SELECT * FROM prueba;
Esto es lo que contiene las tablas fuente y objetivo:
Como podemos observar, las únicas filas que coinciden son las que tienen valores en 2 A y 3 B en las columnas cve y tipo respectivamente. En la siguiente imagen se explica que es lo que realiza dicho MERGE con todas sus cláusulas WHEN

Si tienen alguna duda o comentario al respecto, pueden escribirme.

SALUDOS!
COMPARTE ESTA INFORMACION SI TE PARECIO INTERESANTE

0 comentarios:

Publicar un comentario