Cách tìm ra sự khác biệt về nội dung giữa 2 bảng SQL và tạo SQL đồng bộ


12

Làm cách nào để tìm ra sự khác biệt về dữ liệu giữa hai bảng có lược đồ chính xác và cách tạo SQL đồng bộ hóa để có kết quả hợp nhất (không trùng lặp)?

Đây là 2 bảng:

SOURCE01.dbo.Customers (31,022 rows)

TARGET01.dbo.Customers (29,300 rows)

Lược đồ của mỗi bảng là:

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

Câu trả lời:


6

Khác với tablediff và powershell được đề cập trong các câu trả lời trước, bạn cũng có thể sử dụng SQL với câu lệnh UNION ALL để tìm các bản ghi không khớp trong 2 bảng giống nhau:

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;

Một tùy chọn khác bạn có thể thử là sử dụng So sánh dữ liệu trong chính Visual Studio. Nó so sánh dữ liệu trong cơ sở dữ liệu nguồn và cơ sở dữ liệu đích và tạo tập lệnh đồng bộ hóa cho các bảng bạn đã chọn để đồng bộ hóa.

Và cuối cùng, nhưng không kém phần quan trọng, bạn có thể sử dụng công cụ so sánh dữ liệu SQL - ApexSQL Data Diff , để đặt tất cả các tùy chọn đồng bộ hóa, ánh xạ các bảng và cột với các tên khác nhau, tạo các khóa của riêng bạn để so sánh trong GUI. Bạn có thể lên lịch để chạy không giám sát và tất cả những gì bạn phải làm là kiểm tra lịch sử công việc của SQL Server vào buổi sáng. Nếu bạn cần biết thêm chi tiết về các tùy chọn này, tôi khuyên bạn nên đọc bài viết này: http://solutioncenter.apexsql.com/automatically-compare-and-syn syncize-sql-server-data /


6

Thật đáng ngạc nhiên khi không ai đề cập rằng điều này được tích hợp vào SQL Server Data Tools. Mặc dù chức năng là cơ bản khi so sánh với Redgate chẳng hạn.

Một số chi tiết trong So sánh và đồng bộ hóa dữ liệu trong một hoặc nhiều bảng với dữ liệu trong cơ sở dữ liệu tham chiếu


1
Đó có thể là vì vào năm tháng 5 năm 2014, không có SSDT? Thật tốt khi bạn đặt câu trả lời này :-)
Kin Shah

4

Sử dụng các công cụ bản địa:

tablediff : tiện ích tablediff so sánh dữ liệu trong bảng nguồn với bảng trong bảng đích.

powershell: so sánh-object cho phép bạn đạt được điều đó. đây là một ví dụ tốt

bên thứ ba:

lược đồ lại và so sánh dữ liệu. Bạn thậm chí có thể sử dụng powershell và lược đồ / dữ liệu so sánh để tự động hóa mọi thứ.


3

Tôi đã sử dụng cái này gần đây cho một mục đích tương tự:

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;

Nó không dựa vào khóa chính là nhất quán. Nhưng bạn phải có một cái gì đó phù hợp sau khi tất cả. Một tập lệnh meta để tạo mã như trên là tương đối dễ viết và làm cho các bảng nhiều cột dễ so sánh.

Đối với đồng bộ hóa, bạn sẽ phải source left join targettarget left join sourcesau đó quyết định những gì bạn muốn làm với kết quả của mỗi.


2

Điều này sẽ cung cấp cho bạn sự khác biệt giữa hai bảng, sau đó bạn có thể bọc điều này trong một truy vấn chèn để đặt sự khác biệt từ A vào B hoặc ngược lại.

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

Một trong những công cụ miễn phí của chúng tôi có giao diện đầy đủ cho TableDiff:

http://nobhillsoft.com/Diana.aspx

Ngoài ra, hãy kiểm tra công cụ so sánh DB của chúng tôi. Đây là người duy nhất ngoài đó so sánh lượng dữ liệu không giới hạn (không phải dữ liệu nào khác có thể thực hiện hàng triệu triệu bản ghi) miễn là bạn so sánh giữa 2 máy chủ được liên kết

http://nobhillsoft.com/NHDBCompare.aspx

(chúng tôi đã thấy các liên kết khác trong chuỗi này cho các sản phẩm của bên thứ 3 vì vậy chúng tôi tin rằng nó hợp pháp để đề cập đến chúng tôi ... vui lòng cho chúng tôi biết nếu không phải vậy)


2
AFAIK là hợp pháp miễn là nó là một câu trả lời hữu ích cho một câu hỏi chính hãng và bạn nói rằng bạn có kết nối với sản phẩm. Vì vậy, sẽ nghĩ rằng nó tốt.
Martin Smith

1

Nếu cả hai bảng có các khóa chính tương tự nhau, bạn có thể sử dụng chiến lược bên dưới để so sánh các bảng nguồn và bảng đích: (Tôi đã đánh dấu các cột khóa tổng hợp bằng dấu hoa thị)

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

Điều này hoạt động bởi vì công đoàn ngầm trả lại hồ sơ riêng biệt. Vì vậy, đối với bất kỳ hàng đã cho nào (được xác định bởi một số khóa) trong nguồn mà bạn mong đợi khớp chính xác trong mục tiêu, bạn sẽ mong đợi một liên kết của src và mục tiêu trả về 1 hàng cho bất kỳ khóa nào. Do đó, bạn có thể sử dụng chiến lược trên để tìm ra khóa nào trả về kết quả hợp nhất có nhiều hàng, sau đó truy vấn lại mục tiêu kết hợp src, (lần này chỉ chọn các bản ghi có sự khác biệt bằng cách nối với bảng diff) chọn tất cả các cột bạn muốn so sánh, sắp xếp theo các cột soạn thảo khóa và bạn sẽ thấy chính xác cột nào không khớp. Lưu ý rằng các tên cột trong nguồn và đích không cần phải khớp, vì chúng có thể được đặt bí danh cho nhau bằng cách sử dụng câu lệnh "as".


0

Để tìm sự khác nhau giữa hai bảng giống hệt

SELECT *
TỪ SOURCE01.dbo.Customers

UNION

SELECT *
TỪ TARGET01.dbo.Customers

TRỪ

SELECT *
TỪ SOURCE01.dbo.Customers

INTERSECT

SELECT *
TỪ TARGET01.dbo.Customers


Thứ tự các thao tác làm cho INTERSECT được thực hiện trước tiên sẽ cung cấp cho bạn một tập dữ liệu chỉ các hàng tồn tại trong cả hai bảng. Thứ hai, UNION được thực hiện, cung cấp cho bạn tất cả các hàng từ cả hai bảng mà không trùng lặp. Cuối cùng, EXCEPT được thực hiện để xóa khỏi UNION của bạn (tất cả các hàng của cả hai bảng) bộ dữ liệu INTERSECT là các hàng trong cả hai bảng. Điều này để lại cho bạn một tập dữ liệu chỉ chứa các hàng tồn tại trong một trong các bảng chứ không phải trong các bảng khác. Nếu tập dữ liệu của bạn trở lại trống thì tất cả các hàng giống nhau giữa các bảng.



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


Này đó! Tôi nghĩ rằng câu trả lời của bạn sẽ tốt hơn nếu bạn sử dụng tên bảng từ câu hỏi ban đầu!
Anthony Genovese

0

Tôi đã có một vấn đề tương tự và đã sử dụng lệnh 'EXCEPT' của SQL để giải quyết vấn đề. Lệnh EXCEPT nhận hai câu lệnh SELECT và trả về các hàng được trả về bởi câu lệnh SELECT đầu tiên (trái) và không phải bởi câu lệnh SELECT thứ hai (phải).

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

PS: Lược đồ cho cả hai bảng được trả về bởi câu lệnh SELECT phải khớp.

Để rõ hơn, hãy truy cập: Trang hướng dẫn tại đây


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)

Tập lệnh (khi được cung cấp với các chi tiết có liên quan) so sánh 2 bảng (giả sử Khách hàng trên máy chủ1 với Khách hàng trên Máy chủ2).

Kịch bản này sẽ hữu ích nếu bạn so sánh một bảng có nhiều cột nhưng đấu tranh để tìm cột không khớp chính xác.

Tôi có một bảng có 353 cột và tôi phải so sánh nó với một bảng khác và tìm thấy với các giá trị không khớp và tập lệnh này sẽ giúp bạn xác định bộ dữ liệu chính xác.


-1

Tôi nghĩ bạn nên thử so sánh dữ liệu xQuery , việc này sẽ thực hiện thủ thuật trong trường hợp của bạn. Ví dụ, giả sử bạn chỉ định

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

Sau khi bạn so sánh các bảng, trong kết quả so sánh, bạn có thể chỉ định rằng bạn chỉ muốn đồng bộ hóa các khác biệt từ bảng bên trái sẽ tạo tập lệnh SQL để chèn vào TARGET01.dbo. Khách hàng tất cả các hàng không nằm trong bảng này nhưng tồn tại trong SOURCE01.dbo.Customers (Đạt được kết quả UNION mà không cần trùng lặp). Hi vọng điêu nay co ich!

Tiết lộ: Tôi đang liên kết với xQuery.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.