Come scoprire le differenze di contenuto tra 2 tabelle SQL e produrre SQL di sincronizzazione


12

Come faccio a scoprire le differenze nei dati tra le due tabelle che hanno lo schema esatto e come produrre SQL di sincronizzazione per ottenere i risultati del sindacato (senza duplicati)?

Queste sono le 2 tabelle:

SOURCE01.dbo.Customers (31,022 rows)

TARGET01.dbo.Customers (29,300 rows)

Lo schema di ogni tabella è:

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

Risposte:


6

Oltre a tablediff e powershell menzionati nelle risposte precedenti, puoi anche usare SQL con l'istruzione UNION ALL per trovare i record che non corrispondono in 2 tabelle identiche:

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;

Un'altra opzione che puoi provare è utilizzare Data Compare in Visual Studio stesso. Confronta i dati nel database di origine e nel database di destinazione e crea uno script di sincronizzazione per le tabelle selezionate per la sincronizzazione.

E, ultimo ma non meno importante, è possibile utilizzare lo strumento di confronto dei dati SQL - ApexSQL Data Diff , per impostare tutte le opzioni di sincronizzazione, mappare le tabelle e le colonne con nomi diversi, creare le proprie chiavi per il confronto nella GUI. È possibile pianificare l'esecuzione automatica e tutto ciò che è necessario fare è controllare la cronologia dei processi di SQL Server al mattino. Se hai bisogno di maggiori dettagli su queste opzioni, ti consiglio di leggere questo articolo: http://solutioncenter.apexsql.com/automatically-compare-and-synchronize-sql-server-data/



4

Utilizzando strumenti nativi:

tablediff : l' utilità tablediff confronta i dati nella tabella di origine con la tabella nella tabella di destinazione.

powershell: compare-object ti permette di raggiungere questo obiettivo. ecco un buon esempio

terzo:

schema di redgate e confronto dei dati. Puoi anche usare PowerShell e il confronto di schemi / dati per automatizzare le cose.


3

L'ho usato di recente per uno scopo simile:

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;

Si basa sulla coerenza della chiave primaria. Ma dopo tutto devi avere qualcosa di coerente. Un meta script per generare codice come quello sopra è relativamente semplice da scrivere e semplifica il confronto di tabelle a più colonne.

Per quanto riguarda la sincronizzazione dovrai source left join targete target left join source, quindi, decidere cosa vuoi fare con il risultato di ciascuno.


2

Questo dovrebbe darti le differenze tra le due tabelle, quindi puoi racchiuderlo in una query di inserimento per inserire le differenze da A in 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

Uno dei nostri strumenti gratuiti ha un'interfaccia completa per TableDiff:

http://nobhillsoft.com/Diana.aspx

Inoltre, controlla il nostro strumento di confronto DB. È l'unico là fuori che confronta una quantità illimitata di dati (nessuno degli altri può fare milioni e milioni di record) ... fintanto che si confronta tra 2 server collegati

http://nobhillsoft.com/NHDBCompare.aspx

(abbiamo visto altri collegamenti in questa discussione per prodotti di terze parti, quindi crediamo che sia legittimo menzionare il nostro ... per favore fateci sapere se non lo è)


2
AFAIK è legale purché sia ​​una risposta ontopica a una domanda autentica e dichiari di avere una connessione con il prodotto. Quindi avrei pensato che andasse bene.
Martin Smith,

1

Se entrambe le tabelle hanno chiavi primarie simili, puoi utilizzare la seguente strategia per confrontare le tabelle di origine e di destinazione: (Ho contrassegnato le colonne chiave composita 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

Questo funziona perché l'unione restituisce implicitamente record distinti. Quindi, per una data riga (identificata da una chiave) nella sorgente che prevedi corrisponda esattamente alla destinazione, ti aspetteresti che un'unione di src e destinazione restituisca 1 riga per una determinata chiave. Quindi puoi usare la strategia di cui sopra per scoprire quali chiavi restituiscono un risultato di unione con più righe, quindi interrogare nuovamente il target di unione src (questa volta selezionando solo i record con differenze unendoti alla tabella diff) selezionando tutte le colonne che desideri confronta, ordinando per colonne che compongono la chiave, e vedrai esattamente quali colonne non corrispondono. Nota che i nomi delle colonne nell'origine e nella destinazione non devono corrispondere, poiché possono essere aliasati tra loro usando un'istruzione "as".


0

Per trovare le differenze tra due tabelle identiche

SELEZIONA *
DA SOURCE01.dbo.Customers

UNION

SELECT *
DA TARGET01.dbo.Customers

SALVA

SELEZIONA *
DA SOURCE01.dbo.Customers

INTERSECT

SELECT *
DA TARGET01.dbo.Customers


L'ordine delle operazioni fa sì che INTERSECT venga eseguito per primo, il che ti darà un set di dati di sole righe che esistono in entrambe le tabelle. In secondo luogo viene eseguita l'UNION che fornisce tutte le righe da entrambe le tabelle senza duplicati. Infine, viene eseguito EXCEPT che elimina da UNION (tutte le righe di entrambe le tabelle) il set di dati INTERSECT che è le righe in entrambe le tabelle. Questo ti lascia con un set di dati contenente solo le righe esistenti in una delle tabelle ma non nell'altra. Se il set di dati torna vuoto, tutte le righe sono uguali tra le tabelle.



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


Ehilà! Penso che la tua risposta sarebbe migliore se tu usassi i nomi delle tabelle dalla domanda originale!
Anthony Genovese,

0

Ho avuto un problema simile e ho usato il comando SQL 'EXCEPT' per risolvere il problema. Il comando EXCEPT accetta due istruzioni SELECT e restituisce le righe restituite dalla prima istruzione SELECT (a sinistra) e non dalla seconda (a destra) SELECT.

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

PS: lo schema per entrambe le tabelle restituite dall'istruzione SELECT deve corrispondere.

Per maggiore chiarezza, visitare: Pagina dei punti Tutorial qui


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)

Lo script (se fornito con i dettagli pertinenti) confronta 2 tabelle (ad esempio Clienti sul server1 con Clienti sul Server2).

Questo script sarà utile se stai confrontando una tabella con molte colonne ma fai fatica a trovare la colonna di mancata corrispondenza esatta.

Ho una tabella con 353 colonne e ho dovuto confrontarla con un'altra tabella e trovare i valori non corrispondenti e questo script ti aiuterà a individuare la tupla esatta.


-1

Penso che dovresti provare xSQL Data Compare , che farà il trucco nel tuo caso. Diciamo ad esempio che hai specificato

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

Dopo aver confrontato le tabelle, nel risultato del confronto, è possibile specificare che si desidera sincronizzare solo le differenze dalla tabella di sinistra che produrrebbe uno script SQL da inserire in TARGET01.dbo. I clienti tutte le righe che non sono in questa tabella ma esiste in SOURCE01.dbo.Customers (Ottenere un risultato UNION senza duplicati). Spero che sia di aiuto!

Divulgazione: sono affiliato a xSQL.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.