วิธีค้นหาความแตกต่างของเนื้อหาระหว่าง 2 ตาราง SQL และสร้างข้อมูลให้ตรงกัน SQL


13

ฉันจะค้นหาความแตกต่างของข้อมูลระหว่างสองตารางที่มี schema ที่แน่นอนได้อย่างไรและจะสร้าง SQL การซิงโครไนซ์เพื่อให้ได้ผลลัพธ์สหภาพ (โดยไม่ซ้ำกัน) ได้อย่างไร

นี่คือ 2 ตาราง:

SOURCE01.dbo.Customers (31,022 rows)

TARGET01.dbo.Customers (29,300 rows)

สคีมาของแต่ละตารางคือ:

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

คำตอบ:


7

นอกเหนือจาก tablediff และ powershell ที่กล่าวถึงในคำตอบก่อนหน้าคุณยังสามารถใช้ SQL พร้อมกับคำสั่ง UNION ALL เพื่อค้นหาระเบียนที่ไม่ตรงกันในตารางที่เหมือนกัน 2 ตาราง:

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;

ตัวเลือกอื่นที่คุณสามารถลองใช้คือการเปรียบเทียบข้อมูลใน Visual Studio เอง มันเปรียบเทียบข้อมูลในฐานข้อมูลต้นทางและฐานข้อมูลเป้าหมายและสร้างสคริปต์การซิงโครไนซ์สำหรับตารางที่คุณเลือกสำหรับการซิงโครไนซ์

และสุดท้าย แต่ไม่ท้ายสุดคุณสามารถใช้เครื่องมือเปรียบเทียบข้อมูล SQL - ApexSQL Data Diffเพื่อตั้งค่าตัวเลือกการซิงโครไนซ์แมปตารางและคอลัมน์ที่มีชื่อแตกต่างกันสร้างคีย์ของคุณเองเพื่อเปรียบเทียบใน GUI คุณสามารถกำหนดเวลาให้เรียกใช้แบบไม่ต้องใส่ข้อมูลและสิ่งที่คุณต้องทำคือตรวจสอบประวัติงานของ SQL Server ในตอนเช้า หากคุณต้องการรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกเหล่านี้ฉันขอแนะนำให้อ่านบทความนี้: http://solutioncenter.apexsql.com/automatically-compare-and-synchronize-sql-server-data/


6

ค่อนข้างแปลกใจที่ไม่มีใครบอกว่าสิ่งนี้ถูกสร้างไว้ใน SQL Server Data Tools แม้ว่าฟังก์ชั่นพื้นฐานเมื่อเทียบกับ Redgate เช่น

รายละเอียดบางอย่างในการเปรียบเทียบและซิงโครไนซ์ข้อมูลในหนึ่งตารางขึ้นไปพร้อมข้อมูลในฐานข้อมูลอ้างอิง


1
อาจเป็นเพราะในเดือนพฤษภาคม 2557 ไม่มี SSDT หรือไม่ ดีที่คุณตอบคำถามนี้ :-)
Kin Shah

4

ใช้เครื่องมือพื้นเมือง:

tablediff : ยูทิลิตี้ tablediffเปรียบเทียบข้อมูลในตารางต้นฉบับกับตารางในตารางปลายทาง

PowerShell: การเปรียบเทียบวัตถุช่วยให้คุณบรรลุเป้าหมายนั้น นี่เป็นตัวอย่างที่ดี

บุคคลที่สาม:

เปรียบเทียบสคีมาและข้อมูลใหม่ คุณสามารถใช้ powershell และ schema / data เพื่อเปรียบเทียบสิ่งต่าง ๆ โดยอัตโนมัติ


3

ฉันใช้สิ่งนี้เมื่อเร็ว ๆ นี้เพื่อจุดประสงค์ที่คล้ายกัน:

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;

มันขึ้นอยู่กับคีย์หลักที่สอดคล้องกัน แต่คุณต้องมีสิ่งที่สอดคล้องกันหลังจากทั้งหมด เมตาสคริปต์ในการสร้างรหัสเช่นด้านบนนั้นค่อนข้างง่ายต่อการเขียนและทำให้ตารางหลายคอลัมน์นั้นง่ายต่อการเปรียบเทียบ

สำหรับการประสานคุณจะต้องsource left join targetและtarget left join sourceจากนั้นตัดสินใจว่าคุณต้องการจะทำอย่างไรกับผลลัพธ์ของแต่ละคน


2

สิ่งนี้จะให้ความแตกต่างระหว่างสองตารางจากนั้นคุณสามารถใส่คำสั่งนี้ลงในคิวรีแทรกเพื่อนำความแตกต่างจาก A ไปเป็น B หรือในทางกลับกัน

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

หนึ่งในเครื่องมือฟรีของเรามีส่วนต่อประสานแบบเต็มสำหรับ TableDiff:

http://nobhillsoft.com/Diana.aspx

นอกจากนี้ตรวจสอบเครื่องมือการเปรียบเทียบฐานข้อมูลของเรา มันเป็นสิ่งเดียวเท่านั้นที่มีการเปรียบเทียบจำนวนข้อมูลไม่ จำกัด (ไม่ใช่ของคนอื่น ๆ สามารถทำล้านและล้านระเบียน) ... ตราบใดที่คุณเปรียบเทียบระหว่าง 2 เซิร์ฟเวอร์ที่เชื่อมโยง

http://nobhillsoft.com/NHDBCompare.aspx

(เราเห็นลิงค์อื่น ๆ ในหัวข้อนี้สำหรับผลิตภัณฑ์ของบุคคลที่สามดังนั้นเราจึงเชื่อว่าถูกต้องตามกฎหมายที่จะพูดถึงของเรา ... กรุณาแจ้งให้เราทราบหากมันไม่ได้)


2
AFAIK เป็นเรื่องถูกต้องตราบใดที่ยังเป็นคำตอบแบบ ontopic สำหรับคำถามของแท้และคุณระบุว่าคุณมีการเชื่อมต่อกับผลิตภัณฑ์ ดังนั้นจะคิดว่ามันดี
Martin Smith

1

หากทั้งสองตารางมีคีย์หลักที่คล้ายกันคุณสามารถใช้กลยุทธ์ด้านล่างเพื่อเปรียบเทียบตารางต้นทางและเป้าหมาย: (ฉันทำเครื่องหมายคอลัมน์คีย์ผสมกับเครื่องหมายดอกจัน)

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

งานนี้เพราะสหภาพส่งกลับบันทึกที่แตกต่างกันโดยปริยาย ดังนั้นสำหรับแถวใด ๆ ที่ระบุ (ระบุโดยบางคีย์) ในแหล่งที่คุณคาดหวังว่าจะตรงในเป้าหมายคุณจะคาดหวังว่าจะมีการรวมกันของ src และเป้าหมายเพื่อส่งกลับ 1 แถวสำหรับคีย์ที่กำหนด ดังนั้นคุณสามารถใช้กลยุทธ์ด้านบนเพื่อค้นหาว่าคีย์ใดส่งคืนผลลัพธ์การรวมที่มีหลายแถวจากนั้นค้นหาเป้าหมายสหภาพ src อีกครั้ง (คราวนี้เลือกระเบียนที่มีความแตกต่างโดยการเข้าร่วมกับตาราง diff) เลือกคอลัมน์ทั้งหมดที่คุณต้องการ เปรียบเทียบเรียงลำดับโดยคอลัมน์เขียนคีย์และคุณจะเห็นว่าคอลัมน์ใดไม่ตรงกัน โปรดทราบว่าชื่อคอลัมน์ในแหล่งที่มาและเป้าหมายไม่จำเป็นต้องตรงกันเนื่องจากสามารถใช้ชื่อแทนกันได้โดยใช้คำสั่ง "as"


0

หากต้องการค้นหาความแตกต่างระหว่างสองตารางที่เหมือนกัน

SELECT *
จาก SOURCE01.dbo.Customers

UNION

SELECT *
จาก TARGET01.dbo.Customers

ยกเว้น

SELECT *
FROM SOURCE01.dbo.Customers

INTERSECT

SELECT *
จาก TARGET01.dbo.Customers


ลำดับของการดำเนินการทำให้ INTERSECT ถูกดำเนินการก่อนซึ่งจะให้ชุดข้อมูลของแถวที่มีอยู่ในตารางทั้งสองเท่านั้น ประการที่สองยูเนี่ยนจะดำเนินการซึ่งจะช่วยให้คุณแถวทั้งหมดจากทั้งสองตารางโดยไม่ซ้ำกัน ในที่สุด EXCEPT จะดำเนินการซึ่งลบออกจาก UNION ของคุณ (ทุกแถวของตารางทั้งสอง) ชุดข้อมูล INTERSECT ซึ่งเป็นแถวในตารางทั้งสอง สิ่งนี้ทำให้คุณมีชุดข้อมูลที่มีเฉพาะแถวที่มีอยู่ในหนึ่งในตาราง แต่ไม่ใช่ในอีกชุดหนึ่ง หากชุดข้อมูลของคุณกลับมาว่างเปล่าแถวทั้งหมดจะเหมือนกันระหว่างตาราง



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


สวัสดี! ฉันคิดว่าคำตอบของคุณจะดีกว่าถ้าคุณใช้ชื่อตารางจากคำถามเดิม!
Anthony Genovese

0

ฉันมีปัญหาที่คล้ายกันและใช้คำสั่ง SQL 'ยกเว้น' เพื่อแก้ปัญหา คำสั่งยกเว้นใช้คำสั่ง SELECT สองคำสั่งและส่งคืนแถวที่ส่งคืนโดยคำสั่ง SELECT แรก (ซ้าย) และไม่ใช่ตามคำสั่ง SELECT ที่สอง (ขวา)

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

PS: schema สำหรับทั้งตารางที่ส่งคืนโดยคำสั่ง SELECT ต้องตรงกัน

สำหรับความชัดเจนเพิ่มเติมโปรดไปที่: หน้าบทช่วยสอนที่นี่


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)

สคริปต์ (เมื่อให้ข้อมูลรายละเอียดที่เกี่ยวข้อง) เปรียบเทียบ 2 ตาราง (พูดลูกค้าในเซิร์ฟเวอร์ 1 กับลูกค้าในเซิร์ฟเวอร์ 2)

สคริปต์นี้จะมีประโยชน์หากคุณกำลังเปรียบเทียบตารางกับคอลัมน์จำนวนมาก แต่พยายามหาคอลัมน์ที่ไม่ตรงกัน

ฉันมีตารางที่มี 353 คอลัมน์และฉันต้องเปรียบเทียบกับตารางอื่นและค้นหาด้วยค่าที่ไม่ตรงกันและสคริปต์นี้จะช่วยคุณค้นหา tuple ที่แน่นอน


-1

ฉันคิดว่าคุณควรลองเปรียบเทียบข้อมูล xSQLซึ่งจะทำเคล็ดลับในกรณีของคุณ สมมติว่าเป็นตัวอย่างที่คุณระบุ

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

หลังจากที่คุณเปรียบเทียบตารางในผลลัพธ์การเปรียบเทียบคุณสามารถระบุว่าคุณต้องการซิงค์เฉพาะความแตกต่างจากตารางด้านซ้ายซึ่งจะสร้างสคริปต์ SQL เพื่อแทรกลงใน TARGET01.dbo ลูกค้าแถวทั้งหมดที่ไม่ได้อยู่ในตารางนี้แต่ มีอยู่ใน SOURCE01.dbo.Customers (บรรลุผลลัพธ์ยูเนี่ยนโดยไม่ซ้ำกัน) หวังว่านี่จะช่วยได้!

การเปิดเผยข้อมูล: ฉันเข้าร่วมกับ xSQL

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.