none
SQL Merge no respeta condición WHEN MATCHED RRS feed

  • Pregunta

  • Buen día expertos, me enfrento con un problema de SQL.

    En un sistema donde se cargan Estados de Cuenta en formato Excel usando BulkCopy, requiero que al cargar un nuevo documento, se busque si hay registros duplicados, y en caso afirmativo, ignore los que se habían cargado previamente y sólo inserte las nuevas líneas que correspondan.

    Por desgracia, éstos estados de cuenta no tienen un ID único para cada fila, por lo que necesito buscar una alternativa para encontrar duplicados.

    La manera que se me ocurrió es primero crear dos tablas, una definitiva u objetivo donde está el conjunto de todos los registros, y una temporal en donde cargaré el nuevo archivo, ejecutaré un query para identificar los que se necesiten ignorar y los que si procedan se insertarán, por último limpiar la tabla temporal.

    Este es un ejemplo de mi tabla objetivo, la cual ya tiene cargados tres registros:

    Tabla objetivo

    La tabla temporal es igual, salvo que no contiene la columna ID. El query que ejecuto al cargar un archivo es el siguiente:

    MERGE Pagos_EDC_Final T 
    USING Pagos_EDC_Temp S
    ON (
    		T.Banco = S.Banco AND 
    		T.Fecha = S.Fecha AND 
    		T.Hora = S.Hora AND 
    		T.Referencia = S.Referencia AND 
    		T.Narrativa = S.Narrativa  AND 
    		T.SucBanco = S.SucBanco  AND 
    		T.CodigoMov = S.CodigoMov  AND 
    		T.Concepto = S.Concepto  AND 
    		T.Importe = S.Importe
    	)
    
    WHEN MATCHED
        THEN UPDATE SET 
    		T.Banco = S.Banco
    
    WHEN NOT MATCHED BY TARGET 
        THEN INSERT (Banco, Fecha, FechaCarga, Hora, Referencia, Narrativa, SucBanco, CodigoMov, Concepto, Importe, Vendedor, Memo, Cliente)
             VALUES (S.Banco, S.Fecha, S.FechaCarga, S.Hora, S.Referencia, S.Narrativa, S.SucBanco, S.CodigoMov, S.Concepto, S.Importe, S.Vendedor, S.Memo, S.Cliente);
    
    DELETE FROM Pagos_EDC_Temp;

    El problema es que no me respeta la cláusula WHEN MATCHED, debido a que cargo un archivo con 10 registros, donde los primeros tres son duplicados y coinciden en todas las columnas especificadas dentro del ON, sin embargo, los inserta en la tabla objetivo de igual forma como se muestra a continuación:

    Registros duplicados

    He intentado quitar la columna ID para que ambas tablas tengan la misma estructura, quitar la cláusula WHEN MATCHED, cambiar la condición de NOT MATCHED quitando BY TARGET, pero ninguno de estos intentos ha dado el resultado esperado.

    Agradezco de antemano cualquier consejo que puedan darme ya que se agotaron mis ideas para resolver este problema.

    Saludos cordiales.

    martes, 29 de octubre de 2019 22:27

Respuestas

  • Hola LuisVillareal:

    Como te ha explicado José Diz, el problema viene dado por tus columnas null, pero para eso puedes utilizar isnull.

    CREATE TABLE PAGOS_EDC_FINAL (
    ID INT IDENTITY(1,1),
    BANCO VARCHAR(100),
    FECHA DATE,
    FECHACARGA DATETIME DEFAULT CURRENT_TIMESTAMP,
    HORA TIME,
    REFERENCIA VARCHAR(15),
    NARRATIVA VARCHAR(100),
    SUCBANCO INT,
    CODIGOMOV INT,
    CONCEPTO VARCHAR(100),
    IMPORTE DECIMAL(10,2),
    VENDEDOR VARCHAR(100),
    MEMO VARCHAR(100),
    CLIENTE VARCHAR(100)
    );
    CREATE TABLE PAGOS_EDC_TEMP (
    ID INT IDENTITY(1,1),
    BANCO VARCHAR(100),
    FECHA DATE,
    FECHACARGA DATETIME DEFAULT CURRENT_TIMESTAMP,
    HORA TIME,
    REFERENCIA VARCHAR(15),
    NARRATIVA VARCHAR(100),
    SUCBANCO INT,
    CODIGOMOV INT,
    CONCEPTO VARCHAR(100),
    IMPORTE DECIMAL(10,2),
    VENDEDOR VARCHAR(100),
    MEMO VARCHAR(100),
    CLIENTE VARCHAR(100)
    );
    GO
    
    INSERT  INTO PAGOS_EDC_FINAL 
    (BANCO,
     FECHA,
     FECHACARGA,
     HORA,
     REFERENCIA,
     NARRATIVA,
     SUCBANCO,
     CODIGOMOV, 
     CONCEPTO,
     IMPORTE,
     VENDEDOR,
     MEMO,
     CLIENTE)
     VALUES
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698347','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 25588.13,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698420','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 15243.77,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698461','DEPOSITO VENTAS NET...',NULL, NULL, NULL,   199.17,'Sin asignar','Sin asignar','Sin asignar');
     GO
     INSERT INTO PAGOS_EDC_TEMP
     (BANCO,
     FECHA,
     FECHACARGA,
     HORA,
     REFERENCIA,
     NARRATIVA,
     SUCBANCO,
     CODIGOMOV, 
     CONCEPTO,
     IMPORTE,
     VENDEDOR,
     MEMO,
     CLIENTE)
     VALUES
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698347','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 25588.13,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698420','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 15243.77,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698461','DEPOSITO VENTAS NET...',NULL, NULL, NULL,   199.17,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698982','DEPOSITO VENTAS NET...',NULL, NULL, NULL,  2292.14,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698347','pago glassfiber...',NULL, NULL, NULL,  1850.20,'Sin asignar','Sin asignar','Sin asignar');
     GO
    MERGE Pagos_EDC_Final T 
    USING Pagos_EDC_Temp S
    ON (
    		ISNULL(T.Banco     ,'')		    = ISNULL(S.Banco      ,'')		    AND
    		ISNULL(T.Fecha     ,'19000101') = ISNULL(S.Fecha      ,'19000101') 	AND
    		ISNULL(T.Hora      ,'08:00')	= ISNULL(S.Hora       ,'08:00')		AND
    		ISNULL(T.Referencia,'')			= ISNULL(S.Referencia ,'')			AND 
    		ISNULL(T.Narrativa ,'')			= ISNULL(S.Narrativa  ,'')			AND 
    		ISNULL(T.SucBanco  ,'')			= ISNULL(S.SucBanco   ,'')			AND
    		ISNULL(T.CodigoMov ,'')			= ISNULL(S.CodigoMov  ,'')			AND 
    		ISNULL(T.Concepto  ,'')			= ISNULL(S.Concepto   ,'')			AND
    		ISNULL(T.Importe   ,0 )			= ISNULL(S.Importe	  , 0)			
    	)
    
    WHEN MATCHED
        THEN UPDATE SET 
    		T.Banco = S.Banco
    
    WHEN NOT MATCHED BY TARGET 
        THEN INSERT (Banco, Fecha, FechaCarga, Hora, Referencia, Narrativa, SucBanco, CodigoMov, Concepto, Importe, Vendedor, Memo, Cliente)
             VALUES (S.Banco, S.Fecha, S.FechaCarga, S.Hora, S.Referencia, S.Narrativa, S.SucBanco, S.CodigoMov, S.Concepto, S.Importe, S.Vendedor, S.Memo, S.Cliente);
    

    Y con esto la comparación si será efectiva.

    Como no se los tipos de datos, de las columnas, los he creado como me ha parecido en función de la visualización que has puesto.

    Salida

    Por cierto, salvo que tengas un trigger por detrás de la tabla, para que hacer

    WHEN MATCHED
        THEN UPDATE SET 
    		T.Banco = S.Banco
    Si esa condición se va a dar si o si y no va a modificar nada, porque banco = banco

    miércoles, 30 de octubre de 2019 2:29

Todas las respuestas

  • Hola, unas ideas para hacer lo que requieres solo con join.

    Insert de una tabla a otra sin duplicar registros RRS feed


    Votar y marcar respuestas es agradecer.
    Saludos.
    Lima-Perú


    martes, 29 de octubre de 2019 23:21
  • Deleted
    miércoles, 30 de octubre de 2019 1:51
  • Hola LuisVillareal:

    Como te ha explicado José Diz, el problema viene dado por tus columnas null, pero para eso puedes utilizar isnull.

    CREATE TABLE PAGOS_EDC_FINAL (
    ID INT IDENTITY(1,1),
    BANCO VARCHAR(100),
    FECHA DATE,
    FECHACARGA DATETIME DEFAULT CURRENT_TIMESTAMP,
    HORA TIME,
    REFERENCIA VARCHAR(15),
    NARRATIVA VARCHAR(100),
    SUCBANCO INT,
    CODIGOMOV INT,
    CONCEPTO VARCHAR(100),
    IMPORTE DECIMAL(10,2),
    VENDEDOR VARCHAR(100),
    MEMO VARCHAR(100),
    CLIENTE VARCHAR(100)
    );
    CREATE TABLE PAGOS_EDC_TEMP (
    ID INT IDENTITY(1,1),
    BANCO VARCHAR(100),
    FECHA DATE,
    FECHACARGA DATETIME DEFAULT CURRENT_TIMESTAMP,
    HORA TIME,
    REFERENCIA VARCHAR(15),
    NARRATIVA VARCHAR(100),
    SUCBANCO INT,
    CODIGOMOV INT,
    CONCEPTO VARCHAR(100),
    IMPORTE DECIMAL(10,2),
    VENDEDOR VARCHAR(100),
    MEMO VARCHAR(100),
    CLIENTE VARCHAR(100)
    );
    GO
    
    INSERT  INTO PAGOS_EDC_FINAL 
    (BANCO,
     FECHA,
     FECHACARGA,
     HORA,
     REFERENCIA,
     NARRATIVA,
     SUCBANCO,
     CODIGOMOV, 
     CONCEPTO,
     IMPORTE,
     VENDEDOR,
     MEMO,
     CLIENTE)
     VALUES
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698347','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 25588.13,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698420','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 15243.77,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698461','DEPOSITO VENTAS NET...',NULL, NULL, NULL,   199.17,'Sin asignar','Sin asignar','Sin asignar');
     GO
     INSERT INTO PAGOS_EDC_TEMP
     (BANCO,
     FECHA,
     FECHACARGA,
     HORA,
     REFERENCIA,
     NARRATIVA,
     SUCBANCO,
     CODIGOMOV, 
     CONCEPTO,
     IMPORTE,
     VENDEDOR,
     MEMO,
     CLIENTE)
     VALUES
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698347','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 25588.13,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698420','DEPOSITO VENTAS NET...',NULL, NULL, NULL, 15243.77,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698461','DEPOSITO VENTAS NET...',NULL, NULL, NULL,   199.17,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698982','DEPOSITO VENTAS NET...',NULL, NULL, NULL,  2292.14,'Sin asignar','Sin asignar','Sin asignar'),
     ('Banamex Pesos','20191001',DEFAULT,null,'0003698347','pago glassfiber...',NULL, NULL, NULL,  1850.20,'Sin asignar','Sin asignar','Sin asignar');
     GO
    MERGE Pagos_EDC_Final T 
    USING Pagos_EDC_Temp S
    ON (
    		ISNULL(T.Banco     ,'')		    = ISNULL(S.Banco      ,'')		    AND
    		ISNULL(T.Fecha     ,'19000101') = ISNULL(S.Fecha      ,'19000101') 	AND
    		ISNULL(T.Hora      ,'08:00')	= ISNULL(S.Hora       ,'08:00')		AND
    		ISNULL(T.Referencia,'')			= ISNULL(S.Referencia ,'')			AND 
    		ISNULL(T.Narrativa ,'')			= ISNULL(S.Narrativa  ,'')			AND 
    		ISNULL(T.SucBanco  ,'')			= ISNULL(S.SucBanco   ,'')			AND
    		ISNULL(T.CodigoMov ,'')			= ISNULL(S.CodigoMov  ,'')			AND 
    		ISNULL(T.Concepto  ,'')			= ISNULL(S.Concepto   ,'')			AND
    		ISNULL(T.Importe   ,0 )			= ISNULL(S.Importe	  , 0)			
    	)
    
    WHEN MATCHED
        THEN UPDATE SET 
    		T.Banco = S.Banco
    
    WHEN NOT MATCHED BY TARGET 
        THEN INSERT (Banco, Fecha, FechaCarga, Hora, Referencia, Narrativa, SucBanco, CodigoMov, Concepto, Importe, Vendedor, Memo, Cliente)
             VALUES (S.Banco, S.Fecha, S.FechaCarga, S.Hora, S.Referencia, S.Narrativa, S.SucBanco, S.CodigoMov, S.Concepto, S.Importe, S.Vendedor, S.Memo, S.Cliente);
    

    Y con esto la comparación si será efectiva.

    Como no se los tipos de datos, de las columnas, los he creado como me ha parecido en función de la visualización que has puesto.

    Salida

    Por cierto, salvo que tengas un trigger por detrás de la tabla, para que hacer

    WHEN MATCHED
        THEN UPDATE SET 
    		T.Banco = S.Banco
    Si esa condición se va a dar si o si y no va a modificar nada, porque banco = banco

    miércoles, 30 de octubre de 2019 2:29
  • Buen día, muchas gracias por sus respuestas y @Javi te agradezco el que te dieras el tiempo de elaborar y explicar tan a detalle.

    Realicé los cambios que propones incluyendo ISNULL en los campos que aplican y efectivamente ahora si funciona como debe ser y veo el resultado esperado.

    Por último en lo que me preguntas de la condición WHEN MATCHED, tienes razón no hace nada, y originalmente no lo tenía, sólo lo agregué como parte de las pruebas que estaba haciendo para resolverlo. Pero al final lo quité ya que con tu aportación me di cuenta que no es necesaria.

    De nuevo muchas gracias. Un saludo desde Monterrey.

    miércoles, 30 de octubre de 2019 17:09
  • De nada. Un placer
    miércoles, 30 de octubre de 2019 18:32