Finden Sie die inhaltlichen Unterschiede zwischen 2 SQL-Tabellen heraus und erstellen Sie Sync SQL

12

Wie finde ich die Datenunterschiede zwischen den beiden Tabellen mit dem genauen Schema heraus und wie erstelle ich Synchronisations-SQL, um die Vereinigungsergebnisse (ohne Duplikate) zu erhalten?

Dies sind die 2 Tabellen:

SOURCE01.dbo.Customers (31,022 rows)

TARGET01.dbo.Customers (29,300 rows)

Das Schema jeder Tabelle lautet:

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

Antworten:

6

Mit Ausnahme von tablediff und powershell, die in den vorherigen Antworten erwähnt wurden, können Sie SQL auch mit der Anweisung UNION ALL verwenden, um die Datensätze zu finden, die nicht in zwei identischen Tabellen übereinstimmen:

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;

Eine weitere Option, die Sie ausprobieren können, ist die Verwendung von Data Compare in Visual Studio. Es vergleicht Daten in der Quellendatenbank und der Zieldatenbank und erstellt ein Synchronisationsskript für die Tabellen, die Sie für die Synchronisation ausgewählt haben.

Zu guter Letzt können Sie mit dem SQL-Datenvergleichstool - ApexSQL Data Diff - alle Synchronisationsoptionen festlegen, die Tabellen und Spalten mit unterschiedlichen Namen zuordnen und Ihre eigenen Schlüssel für den Vergleich in der GUI erstellen. Sie können festlegen, dass es unbeaufsichtigt ausgeführt wird. Sie müssen lediglich den SQL Server-Auftragsverlauf am Morgen überprüfen. Wenn Sie weitere Informationen zu diesen Optionen benötigen, empfehlen wir Ihnen, diesen Artikel zu lesen: http://solutioncenter.apexsql.com/automatically-compare-and-synchronize-sql-server-data/

Andreas Voller
quelle
3

Ich habe dieses kürzlich für einen ähnlichen Zweck verwendet:

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;

Es setzt voraus, dass der Primärschlüssel konsistent ist. Aber man muss doch etwas Konsequentes haben. Ein Metaskript zum Generieren von Code wie oben ist relativ einfach zu schreiben und erleichtert den Vergleich von mehrspaltigen Tabellen.

Was die Synchronisation angeht, müssen Sie source left join targetund target left join sourcedann entscheiden, was Sie mit dem Ergebnis jedes einzelnen tun möchten.

Michael Green
quelle
2

Dies sollte Ihnen die Unterschiede zwischen den beiden Tabellen geben. Sie können diese dann in eine Einfügeabfrage einbinden, um die Unterschiede von A nach B oder umgekehrt zu setzen.

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)
Reaktionen
quelle
1

Eines unserer kostenlosen Tools verfügt über eine vollständige Oberfläche für TableDiff:

http://nobhillsoft.com/Diana.aspx

Schauen Sie sich auch unser DB-Vergleichstool an. Dies ist der einzige Server, der eine unbegrenzte Datenmenge vergleicht (keiner der anderen kann Millionen und Abermillionen von Datensätzen erstellen) ... solange Sie zwei miteinander verbundene Server vergleichen

http://nobhillsoft.com/NHDBCompare.aspx

(Wir haben andere Links in diesem Thread für Produkte von Drittanbietern gesehen, daher glauben wir, dass es legitim ist, unsere zu erwähnen ... Bitte lassen Sie uns wissen, wenn dies nicht der Fall ist.)

Jonathan Scion
quelle
2
AFAIK ist legitim, solange es sich um eine ontopische Antwort auf eine echte Frage handelt und Sie angeben, dass Sie eine Verbindung zum Produkt haben. Hätte also gedacht, dass es in Ordnung ist.
Martin Smith
1

Wenn beide Tabellen ähnliche Primärschlüssel haben, können Sie die folgende Strategie verwenden, um Quell- und Zieltabellen zu vergleichen: (Ich habe zusammengesetzte Schlüsselspalten mit einem Sternchen markiert.)

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

Dies funktioniert, weil union implizit unterschiedliche Datensätze zurückgibt. Für eine bestimmte Zeile (identifiziert durch einen Schlüssel) in der Quelle, von der Sie erwarten, dass sie genau mit dem Ziel übereinstimmt, würden Sie also erwarten, dass eine Vereinigung von src und target 1 Zeile für einen bestimmten Schlüssel zurückgibt. Auf diese Weise können Sie mit der oben beschriebenen Strategie herausfinden, welche Schlüssel ein Vereinigungsergebnis mit mehreren Zeilen zurückgeben. Anschließend können Sie das Ziel src union erneut abfragen (diesmal nur die Datensätze mit Unterschieden auswählen, indem Sie mit der Diff-Tabelle verbinden) und alle gewünschten Spalten auswählen Vergleichen Sie, indem Sie nach den Spalten sortieren, aus denen der Schlüssel besteht, und Sie sehen genau, welche Spalten nicht übereinstimmen. Beachten Sie, dass die Spaltennamen in der Quelle und im Ziel nicht übereinstimmen müssen, da sie mithilfe einer "as" -Anweisung miteinander verknüpft werden können.

mancini0
quelle
0

Um die Unterschiede zwischen zwei identischen Tabellen zu finden

SELECT *
FROM SOURCE01.dbo.Customers

UNION

SELECT *
FROM TARGET01.dbo.Customers

AUSSER

SELECT *
FROM SOURCE01.dbo.Customers

INTERSECT

SELECT *
FROM TARGET01.dbo.Customers


Die Reihenfolge der Operationen bewirkt, dass zuerst INTERSECT ausgeführt wird, wodurch Sie einen Datensatz erhalten, der nur aus Zeilen besteht, die in beiden Tabellen vorhanden sind. Zweitens wird die UNION ausgeführt, die Ihnen alle Zeilen aus beiden Tabellen ohne Duplikate gibt. Schließlich wird EXCEPT ausgeführt, wodurch der INTERSECT-Datensatz, der die Zeilen in beiden Tabellen darstellt, aus Ihrer UNION (alle Zeilen beider Tabellen) gelöscht wird. Auf diese Weise erhalten Sie ein Dataset, das nur die Zeilen enthält, die in einer der Tabellen vorhanden sind, nicht jedoch in der anderen. Wenn Ihr Dataset wieder leer ist, sind alle Zeilen in den Tabellen gleich.



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

Mihalko
quelle
Sie da! Ich denke, Ihre Antwort wäre besser, wenn Sie die Tabellennamen aus der ursprünglichen Frage verwenden würden!
Anthony Genovese
0

Ich hatte ein ähnliches Problem und habe den SQL-Befehl 'EXCEPT' verwendet, um das Problem zu lösen. Der Befehl EXCEPT verwendet zwei SELECT-Anweisungen und gibt die Zeilen zurück, die von der ersten SELECT-Anweisung (links) und nicht von der zweiten SELECT-Anweisung (rechts) zurückgegeben werden.

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

PS: Das Schema für beide von der SELECT-Anweisung zurückgegebenen Tabellen muss übereinstimmen.

Weitere Informationen finden Sie auf der Seite Tutorials Point hier

avirup.m97
quelle
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)

Das Skript vergleicht (sofern mit den relevanten Details versehen) 2 Tabellen (z. B. Kunden auf Server1 mit Kunden auf Server2).

Dieses Skript ist nützlich, wenn Sie eine Tabelle mit vielen Spalten vergleichen, aber Schwierigkeiten haben, die genaue Spalte mit der falschen Zuordnung zu finden.

Ich habe eine Tabelle mit 353 Spalten und musste sie mit einer anderen Tabelle vergleichen und feststellen, dass die Werte nicht übereinstimmen. Dieses Skript hilft Ihnen dabei, das genaue Tupel zu finden.

user191127
quelle
-1

Ich denke, Sie sollten xSQL Data Compare ausprobieren , was in Ihrem Fall den Trick macht. Nehmen wir zum Beispiel an, dass Sie angeben

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

Nachdem Sie die Tabellen verglichen haben, können Sie im Vergleichsergebnis angeben, dass Sie nur die Unterschiede zur linken Tabelle synchronisieren möchten, die ein SQL-Skript zum Einfügen in TARGET01.dbo erzeugen würden. Verwendet alle Zeilen, die nicht in dieser Tabelle enthalten sind, jedoch existieren in SOURCE01.dbo.Customers (Erreichen eines UNION-Ergebnisses ohne Duplikate). Hoffe das hilft!

Offenlegung: Ich bin mit xSQL verbunden.

Endi Zhupani
quelle