Cómo encontrar las diferencias de contenido entre 2 tablas SQL y producir sincronización SQL


12

¿Cómo descubro las diferencias en los datos entre las dos tablas que tienen un esquema exacto y cómo producir sincronización SQL para obtener los resultados de la unión (sin duplicados)?

Estas son las 2 tablas:

SOURCE01.dbo.Customers (31,022 rows)

TARGET01.dbo.Customers (29,300 rows)

El esquema de cada tabla es:

  • [CustomerId] : nvarchar(255)
  • [CustomerSerializedProfile]: nvarchar(max)
  • [CreatedDatetime] : DateTime

Respuestas:


6

Además de tablediff y powershell mencionados en las respuestas anteriores, también puede usar SQL con la instrucción UNION ALL para encontrar los registros que no coinciden en 2 tablas idénticas:

SELECT MIN(TableName) AS TableName
   ,ID
   ,NAME
   ,lastname
   ,Address
   ,City
FROM (
SELECT 'Table A' AS TableName
    ,Customers.id
    ,Customers.NAME
    ,Customers.lastname
    ,Customers.Address
    ,Customers.City
FROM Customers

UNION ALL

SELECT 'Table B' AS TableName
    ,CustomersOld.id
    ,CustomersOld.NAME
    ,CustomersOld.lastname
    ,CustomersOld.Address
    ,CustomersOld.City
FROM CustomersOld
) tmp
GROUP BY ID
   ,NAME
   ,lastname
   ,Address
   ,City
HAVING COUNT(*) = 1
ORDER BY id;

Otra opción que puede probar es usar Data Compare en Visual Studio. Compara los datos en la base de datos de origen y la base de datos de destino y crea un script de sincronización para las tablas que ha seleccionado para la sincronización.

Y por último, pero no menos importante, puede usar la herramienta de comparación de datos SQL: ApexSQL Data Diff , para configurar todas las opciones de sincronización, mapear las tablas y columnas con diferentes nombres, crear sus propias claves para comparar en la GUI. Puede programarlo para que se ejecute sin supervisión y todo lo que tiene que hacer es verificar el historial de trabajos de SQL Server por la mañana. Si necesita más detalles sobre estas opciones, le recomiendo leer este artículo: http://solutioncenter.apexsql.com/automatically-compare-and-synchronize-sql-server-data/



4

Usando herramientas nativas:

tablediff : la utilidad tablediff compara los datos en la tabla de origen con la tabla en la tabla de destino.

powershell: compare-object le permite lograr eso. aquí hay un buen ejemplo

tercero:

esquema de redgate y comparación de datos. Incluso puede usar powershell y comparar esquemas / datos para automatizar las cosas.


3

He usado este recientemente para un propósito similar:

select
    s.*
    ,t.*
from SOURCE01.dbo.Customers as s
full outer join TARGET01.dbo.Customers as t
    on s.CustomerId = t.CustomerId
where s.CustomerSerializedProfile <> t.CustomerSerializedProfile
or s.CreatedDatetime <> t.CreatedDatetime
or s.CustomerId is NULL
or t.CustomerId is NULL;

Depende de que la clave primaria sea consistente. Pero debes tener algo consistente después de todo. Un meta script para generar código como el anterior es relativamente fácil de escribir y hace que las tablas de muchas columnas sean fáciles de comparar.

En cuanto a la sincronización, deberá hacerlo source left join targety target left join sourceluego decidir qué desea hacer con el resultado de cada uno.


2

Esto debería darle las diferencias entre las dos tablas, luego puede envolver esto en una consulta de inserción para colocar las diferencias de A en B o viceversa.

SELECT A.CustomerId, A.CustomerSerializedProfile, A.CreatedDatetime
  FROM SOURCE01.dbo.Customers A
 WHERE NOT EXISTS (SELECT B.ID
                 FROM TARGET01.dbo.Customers
                WHERE B.CustomerId= A.CustomerId
                  AND B.CustomerSerializedProfile= A.CustomerSerializedProfile
                  AND B.CreatedDatetime= A.CreatedDatetime)

1

Una de nuestras herramientas gratuitas tiene una interfaz completa para TableDiff:

http://nobhillsoft.com/Diana.aspx

Además, consulte nuestra herramienta de comparación de bases de datos. Es el único que compara una cantidad ilimitada de datos (ninguno de los otros puede hacer millones y millones de registros) ... siempre que compare entre 2 servidores que están vinculados

http://nobhillsoft.com/NHDBCompare.aspx

(Vimos otros enlaces en este hilo para productos de terceros, por lo que creemos que es legítimo mencionar el nuestro ... por favor, háganos saber si no es así)


2
AFAIK es legítimo siempre y cuando sea una respuesta atópica a una pregunta genuina y declare que tiene una conexión con el producto. Entonces hubiera pensado que está bien.
Martin Smith

1

Si ambas tablas tienen claves primarias similares, puede usar la siguiente estrategia para comparar las tablas de origen y de destino: (Marqué las columnas de clave compuesta con un asterisco)

with src as (select someCol1*, 
                    someCol2*, 
                    someCol3, 
                    someCol4, 
                    someCol5
             from src_table),

tgt as (select someCol1NameCouldDiffer* as someCol1, 
               someCol2*, 
               someCol3, 
               someCol4, 
               someCol5
        from tgt_table),

--Find which keys have at least 1 non-key column difference:

diffs as (select someCol1, 
                 someCol2 
          from (select all 5 columns 
                from src 
                **union** 
                select all 5 columns 
                from target ) 
           **group by** someCol1, someCol2 
           **having count(*)>1** 

--Reselect all columns you wish to compare from src union target, 
--joining on the keys from "diffs" above to show only records which 
--have data differences.

select * 
from (select all 5 columns 
      from src 
      union 
      select all 5 cols 
       from tgt) t1 
join diffs on t1.someCol1 = diffs.someCol1 
           and t1.someCol2 = diffs.someCol2 
**order by ** someCol1, someCol2 desc

Esto funciona porque la unión devuelve implícitamente registros distintos. Entonces, para cualquier fila dada (identificada por alguna clave) en la fuente que espera que coincida exactamente en el objetivo, esperaría que una unión del src y el objetivo devuelva 1 fila para cualquier clave dada. Por lo tanto, puede usar la estrategia anterior para averiguar qué claves devuelven un resultado de unión que tiene varias filas, luego consultar el objetivo de unión src nuevamente (esta vez solo seleccionando los registros que tienen diferencias uniéndose con la tabla de diferencias) seleccionando todas las columnas que desea compare, ordenando por las columnas que componen la clave, y verá exactamente qué columnas no coinciden. Tenga en cuenta que los nombres de columna en el origen y el destino no tienen por qué coincidir, ya que pueden ser alias entre sí mediante una declaración "como".


0

Para encontrar las diferencias entre dos tablas idénticas

SELECT *
FROM SOURCE01.dbo.Customers

UNION

SELECT *
FROM TARGET01.dbo.Customers

EXCEPT

SELECT *
FROM SOURCE01.dbo.Customers

INTERSECT

SELECT *
FROM TARGET01.dbo.Customers


El orden de las operaciones hace que INTERSECT se realice primero, lo que le dará un conjunto de datos de solo filas que existen en ambas tablas. En segundo lugar, se realiza UNION, que le proporciona todas las filas de ambas tablas sin duplicados. Finalmente, se realiza el EXCEPTO que elimina de su UNION (todas las filas de ambas tablas) el conjunto de datos INTERSECT que son las filas en ambas tablas. Esto lo deja con un conjunto de datos que contiene solo las filas que existen en una de las tablas pero no en la otra. Si su conjunto de datos vuelve vacío, todas las filas son iguales entre las tablas.



https://docs.microsoft.com/en-us/sql/t-sql/language-elements/set-operators-except-and-intersect-transact-sql


¡Hola! ¡Creo que su respuesta sería mejor si usara los nombres de las tablas de la pregunta original!
Anthony Genovese el

0

Tuve un problema similar y utilicé el comando 'EXCEPTO' de SQL para resolver el problema. El comando EXCEPT toma dos instrucciones SELECT y devuelve las filas que devuelve la primera instrucción SELECT (izquierda) y no la segunda (derecha) instrucción SELECT.

SELECT * from table1 where x,y,z 
EXCEPT
SELECT * from table2 where a,b,c

PD: el esquema para ambas tablas devueltas por la instrucción SELECT debe coincidir.

Para mayor claridad, visite: Página de puntos de tutoriales aquí


0
/*
Compare master table data on 2 servers (
1. Change server name
2. Set RaceDate (@racedate) with the >, < ,= >= operator 
 before you run)

 --KNOWN ISSUES
 1. Tables need PKs

*/
SET NOCOUNT ON

--Destination Server Details
DECLARE @destServ nvarchar(40)='[sql\inst23]'    --required             -- If local instance, leave the string empty 
DECLARE @destdb nvarchar(40)='DBName'         --required        
DECLARE @destSchema nvarchar(40)='dbo'        --required        
DECLARE @destTable  nvarchar(40)='TableName'    --required      

-- Source Server Details
DECLARE @SourServ nvarchar(40)='[sql\inst07]'   --required      
DECLARE @Sourdb nvarchar(40)='DBonRemoteServer'  --required     
DECLARE @SourSchema nvarchar(40)='dbo'          --required      
DECLARE @SourTable  nvarchar(40)='TableName'      --required                                -- TableName format 'MyTable'

DECLARE @WHERE nvarchar(400) = 'WHERE 1=1'

DECLARE @Clause nvarchar(400)= 'AND Id > 201808201500000'       --Choose a Predicate to limit data --Start with AND . e.g: 'AND Date > ''20180801'' '

SELECT @WHERE = @WHERE + @Clause

DECLARE @randomtablesuffix nvarchar(5)
SELECT @randomtablesuffix= SUBSTRING(CAST(NEWID() as nvarchar(255)),1,5)


declare @v nvarchar(max), @sql nvarchar(max), @retval nvarchar(max) , @ParamDef nvarchar(400)

--GET Columns List as varchar Columns for HASHBYTES to compare
SELECT @sql='SELECT @vv= COALESCE(@vv,'''')+''CAST(ISNULL(''+ COLUMN_NAME  + '',0) as VARCHAR(''+ 
        CASE WHEN DATA_TYPE IN (''varchar'',''nvarchar'') THEN CAST(CHARACTER_MAXIMUM_LENGTH as varchar(5)) ELSE ''60 '' END +'')) + ''
from '+ @destdb + '.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='+ QUOTENAME(@destTable,'''') + ''

SET @ParamDef = N'@vv nvarchar(max) OUTPUT'
EXEC sp_executesql @sql, @ParamDef, @vv=@v OUTPUT;

SELECT @v= SUBSTRING(@v,0,LEN(@v))

--Keys to JOIN
DECLARE @pkeylistJoinOUT nvarchar(4000)=''
SET @sql='SELECT @pkeylistJoin = ISNULL(@pkeylistJoin,'''') + '' a.''+ QUOTENAME(COLUMN_NAME) + ''=b.''+ QUOTENAME(COLUMN_NAME) + '' AND'' 
    FROM '+@destdb+'.[INFORMATION_SCHEMA].[KEY_COLUMN_USAGE]
    WHERE TABLE_NAME='+ QUOTENAME(@destTable,'''') + ' ORDER BY ORDINAL_POSITION'

SET @ParamDef = N'@pkeylistJoin nvarchar(max) OUTPUT'
EXEC sp_executesql @sql, @ParamDef, @pkeylistJoin=@pkeylistJoinOUT OUTPUT;  

SELECT @pkeylistJoinOUT = REPLACE(REPLACE(REVERSE( SUBSTRING(REVERSE(@pkeylistJoinOUT), CHARINDEX(']', REVERSE(@pkeylistJoinOUT)), LEN(@pkeylistJoinOUT)) ),']',''),'[','')


--Get Column List 

DECLARE @ColumnListOut nvarchar(max)=''
SET @sql='SELECT  @ColumnList=ISNULL(@ColumnList,'''') + COLUMN_NAME + '',''  FROM '+@destdb +'.[INFORMATION_SCHEMA].[COLUMNS] WHERE TABLE_NAME='+QUOTENAME(@destTable,'''')+ ' ORDER BY ORDINAL_POSITION'

SET @ParamDef = N'@ColumnList nvarchar(max) OUTPUT'
EXEC sp_executesql @sql, @ParamDef, @ColumnList=@ColumnListOut OUTPUT;  


SET @ColumnListOut=SUBSTRING(@ColumnListOut,0,LEN(@ColumnListOut))

--Now Compare

SELECT @sql='

SELECT a.* INTO ##_destissues'+@randomtablesuffix+' FROM (
SELECT HASHBYTES (''SHA2_512'','+ @v +')HashVal,'+ @ColumnListOut +' FROM '+@destServ+'.'+@destdb+'.'+@destSchema+'.'+@destTable + ' x WITH (NOLOCK) ' + @WHERE + '
)a 
JOIN (
SELECT HASHBYTES (''SHA2_512'','+@v +')HashVal,'+ @ColumnListOut + ' FROM ' +@SourServ +'.'+ @Sourdb+ '.'+@SourSchema+'.'+ @SourTable +' y WITH (NOLOCK)  ' + @WHERE + '
)
b ON '+@pkeylistJoinOUT + ' AND  a.HashVal <> b.HashVal '

--print @sql

exec (@sql)


SELECT @sql='

SELECT b.* INTO ##_sourceissues'+@randomtablesuffix+ ' FROM (
SELECT HASHBYTES (''SHA2_512'','+ @v +')HashVal,'+ @ColumnListOut +' FROM '+@destServ+'.'+@destdb+'.'+@destSchema+'.'+@destTable + ' x WITH (NOLOCK) ' + @WHERE + '
)a 
JOIN (
SELECT HASHBYTES (''SHA2_512'','+@v +')HashVal,'+ @ColumnListOut + ' FROM ' +@SourServ +'.'+ @Sourdb+ '.'+@SourSchema+'.'+ @SourTable +' y WITH (NOLOCK)  ' + @WHERE + '
)
b ON '+@pkeylistJoinOUT + ' AND  a.HashVal <> b.HashVal '


exec (@sql)

--Get Column List for Pivoting
DECLARE @ColumnListOutasVC nvarchar(max)=''

SET @sql='SELECT  @ColumnList=ISNULL(@ColumnList,'''')+  ''CAST(''+ COLUMN_NAME + '' AS VARCHAR(200)) as ''+ COLUMN_NAME + '',''   FROM ' + @destdb+'.[INFORMATION_SCHEMA].[COLUMNS] WHERE TABLE_NAME='+QUOTENAME(@desttable,'''')


SET @ParamDef = N'@ColumnList nvarchar(max) OUTPUT'
EXEC sp_executesql @sql, @ParamDef, @ColumnList=@ColumnListOutasVC OUTPUT;  

SET @ColumnListOutasVC=SUBSTRING(@ColumnListOutasVC,0,LEN(@ColumnListOutasVC))

--Get PKs as VARCHAR Values

DECLARE @pkeylistJoinOUTVC nvarchar(4000)=''

SET @sql='SELECT @pkeylistJoin = ISNULL(@pkeylistJoin,'''') + ''CAST(''+COLUMN_NAME + '' as varchar(200)) as '' + COLUMN_NAME + ''1,''  FROM '+ @destdb+'.[INFORMATION_SCHEMA].[KEY_COLUMN_USAGE]   WHERE TABLE_NAME='+QUOTENAME(@destTable,'''') + '  ORDER BY ORDINAL_POSITION'

SET @ParamDef = N'@pkeylistJoin nvarchar(max) OUTPUT'
EXEC sp_executesql @sql, @ParamDef, @pkeylistJoin=@pkeylistJoinOUTVC OUTPUT;    
SET @pkeylistJoinOUTVC=SUBSTRING(@pkeylistJoinOUTVC,0,LEN(@pkeylistJoinOUTVC))
--SELECT @pkeylistJoinOUTVC





SET @sql='
select  * INTO ##_destissuedetail'+@randomtablesuffix+ ' from(
select '+ @pkeylistJoinOUTVC + ', ' + @ColumnListOutasVC
                + '
from 
##_destissues'+ @randomtablesuffix+ '
)c UNPIVOT
(
Vals for ColNames in ('+@ColumnListOut+')
) d'

EXEC( @sql)


SET @sql='
select  * INTO ##_sourceissuedetail'+@randomtablesuffix+' from(
select '+ @pkeylistJoinOUTVC + ', ' + @ColumnListOutasVC
                + '
from 
##_sourceissues'+ @randomtablesuffix+'
)c UNPIVOT
(
Vals for ColNames in ('+@ColumnListOut+')
) d'

EXEC( @sql)

SELECT 'Tables to look for data are ##_destissuedetail'+@randomtablesuffix +' and  ##_sourceissuedetail ' +@randomtablesuffix

SET @sql='
SELECT * FROM ##_destissuedetail'+@randomtablesuffix+ '
EXCEPT
SELECT * FROM ##_sourceissuedetail' +@randomtablesuffix

EXEC (@sql)

El script (cuando se proporciona con los detalles relevantes) compara 2 tablas (digamos Clientes en el servidor1 con Clientes en el Servidor2).

Este script será útil si está comparando una tabla con muchas columnas pero le cuesta encontrar la columna que no coincide exactamente.

Tengo una tabla con 353 columnas y tuve que compararla con otra tabla y encontrar que los valores no coincidían y este script lo ayudará a localizar la tupla exacta.


-1

Creo que deberías probar xSQL Data Compare , que hará el truco en tu caso. Digamos, por ejemplo, que especificas

SOURCE01.dbo.Customers as the **left table** and
TARGET01.dbo.Customers as the **right table**

Después de comparar las tablas, en el resultado de la comparación, puede especificar que desea sincronizar solo las diferencias de la tabla izquierda que producirían un script SQL para insertar en TARGET01.dbo. Los clientes todas las filas que no están en esta tabla pero existen en SOURCE01.dbo.Customers (Lograr un resultado UNION sin duplicados). ¡Espero que esto ayude!

Divulgación: estoy afiliado a xSQL.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.