2 개의 SQL 테이블 간의 컨텐츠 차이점을 찾고 동기화 SQL을 생성하는 방법


13

정확한 스키마가있는 두 테이블 간의 데이터 차이를 어떻게 찾습니까? 동기화 결과를 얻기 위해 동기화 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 문과 함께 사용하여 두 개의 동일한 테이블에서 일치하지 않는 레코드를 찾을 수도 있습니다.

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/



4

기본 도구 사용 :

tablediff : tablediff 유틸리티 는 소스 테이블의 데이터를 대상 테이블의 테이블과 비교합니다.

powershell : 비교 객체를 사용하면 얻을 수 있습니다. 여기 좋은 예가 있습니다

타사 :

redgate 스키마와 데이터 비교. Powershell 및 스키마 / 데이터 비교를 사용하여 작업을 자동화 할 수도 있습니다.


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 targettarget 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

또한 DB 비교 도구를 확인하십시오. 무제한의 데이터를 비교할 수있는 유일한 방법입니다 (다른 데이터는 수백만 및 수백만 개의 레코드를 수행 할 수 없음).…

http://nobhillsoft.com/NHDBCompare.aspx

(우리는 타사 제품에 대한이 스레드의 다른 링크를 보았으므로 합법적으로 우리 제품을 언급한다고 생각합니다 ... pls가 아닌 경우 알려주십시오)


2
AFAIK 진정한 질문에 대한 주제별 답변이며 제품과 관련이 있다고 말하면 합법적입니다. 그래서 괜찮다고 생각했을 것입니다.
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

Union은 암시 적으로 고유 한 레코드를 반환하기 때문에 작동합니다. 따라서 소스의 주어진 행 (일부 키로 식별)에 대해 대상에서 정확히 일치 할 것으로 예상되면 src와 대상의 합집합이 주어진 키에 대해 1 행을 반환 할 것으로 기대합니다. 따라서 위의 전략을 사용하여 여러 행이있는 통합 결과를 반환하는 를 찾은 다음 src 통합 대상을 다시 쿼리합니다 (이번에는 diff 테이블과 조인하여 차이점이있는 레코드 만 선택). 키를 구성하는 열을 기준으로 순서를 비교하면 일치하지 않는 열을 정확하게 볼 수 있습니다. 소스와 대상의 열 이름은 "as"문을 사용하여 서로 별칭을 지정할 수 있으므로 일치하지 않아도됩니다.


0

동일한 두 테이블 간의 차이점을 찾으려면

SELECT *
FROM SOURCE01.dbo. 고객

UNION

SELECT *
FROM TARGET01.dbo. 고객

제외

SELECT *
FROM SOURCE01.dbo.Customers

INTERSECT

SELECT *
FROM TARGET01.dbo.Customers


조작 순서에 따라 INTERSECT가 먼저 수행되어 두 테이블에 존재하는 행의 데이터 세트 만 제공합니다. 두 번째로 UNION이 수행되어 두 테이블의 모든 행이 중복되지 않습니다. 마지막으로 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 'EXCEPT'명령을 사용하여 문제를 해결했습니다. EXCEPT 명령은 두 개의 SELECT 문을 사용하고 두 번째 (오른쪽) SELECT 문이 아니라 첫 번째 SELECT 문 (왼쪽)이 반환 한 행을 반환합니다.

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

PS : SELECT 문에서 반환 한 두 테이블의 스키마가 일치해야합니다.

자세한 내용은 Tutorials Point Page here를 방문하십시오.


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 개의 테이블 (예 : server1의 고객과 Server2의 고객)을 비교합니다.

이 스크립트는 테이블을 많은 열과 비교하지만 정확한 불일치 열을 찾는 데 어려움을 겪는 경우 유용합니다.

353 개의 열이있는 테이블이 있고 다른 테이블과 비교하고 값이 일치하지 않는 것을 찾아야합니다.이 스크립트는 정확한 튜플을 찾는 데 도움이됩니다.


-1

나는 당신의 경우에 트릭을 수행 할 xSQL Data Compare을 시도해야한다고 생각합니다 . 예를 들어,

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

테이블을 비교 한 후 비교 결과에서 왼쪽 테이블과의 차이 만 동기화하여 TARGET01.dbo에 삽입 할 SQL 스크립트를 생성하도록 지정할 수 있습니다 .이 테이블에 없는 모든 행 은 고객 이지만 SOURCE01.dbo.Customers에 존재합니다 (중복없이 UNION 결과 달성). 도움이 되었기를 바랍니다!

공개 : 저는 xSQL에 소속되어 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.