回答:
前の回答で言及した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;
試すことができるもう1つのオプションは、Visual Studio自体でデータ比較を使用することです。ソースデータベースとターゲットデータベースのデータを比較し、同期用に選択したテーブルの同期スクリプトを作成します。
最後に、SQLデータ比較ツール-ApexSQL Data Diffを使用して、すべての同期オプションを設定し、テーブルと列を異なる名前でマッピングし、GUIで比較するための独自のキーを作成できます。無人で実行するようにスケジュールすることができ、朝にSQL Serverジョブ履歴を確認するだけです。これらのオプションに関する詳細が必要な場合は、次の記事を読むことをお勧めします。http://solutioncenter.apexsql.com/automatically-compare-and-synchronize-sql-server-data/
意外なことに、これがまだSQL Server Data Toolsに組み込まれていることを述べた人はいません。ただし、Redgateと比較すると、機能は基本的です。
ネイティブツールの使用:
tablediff:tablediffユーティリティは、ソーステーブルのデータを宛先テーブルのテーブルと比較します。
powershell:compare-objectを使用すると、それを実現できます。ここに良い例があります
第三者:
redgateスキーマとデータの比較。Powershellとスキーマ/データ比較を使用して、物事を自動化することもできます。
私は最近これを同様の目的で使用しました:
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
また、DB比較ツールもご覧ください。無制限の量のデータを比較する唯一のものです(他のどれも数百万件のレコードを処理できません)…リンクされている2台のサーバーを比較する限り
http://nobhillsoft.com/NHDBCompare.aspx
(サードパーティ製品のこのスレッドには他のリンクがありましたので、その正当性に言及していると信じています...そうでない場合はお知らせください)
両方のテーブルに同様の主キーがある場合、以下の戦略を使用してソーステーブルとターゲットテーブルを比較できます(複合キー列にアスタリスクを付けました)。
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」ステートメントを使用して相互にエイリアスを作成できるため、一致する必要はありません。
2つの同一のテーブルの違いを見つけるには
SELECT *
FROM SOURCE01.dbo.Customers
UNION
SELECT *
FROM TARGET01.dbo.Customers
EXCEPT
SELECT *
FROM SOURCE01.dbo.Customers
INTERSECT
SELECT *
FROM TARGET01.dbo.Customers
操作の順序により、INTERSECTが最初に実行され、両方のテーブルに存在する行のみのデータセットが提供されます。次に、UNIONが実行され、重複することなく両方のテーブルのすべての行が提供されます。最後に、両方のテーブルの行であるINTERSECTデータセットをUNION(両方のテーブルのすべての行)から削除するEXCEPTが実行されます。これにより、一方のテーブルには存在するが他方には存在しない行のみを含むデータセットが残ります。データセットが空に戻った場合、すべての行はテーブル間で同じです。
https://docs.microsoft.com/en-us/sql/t-sql/language-elements/set-operators-except-and-intersect-transact-sql
同様の問題があり、SQLの「EXCEPT」コマンドを使用して問題を解決しました。EXCEPTコマンドは2つのSELECTステートメントを受け取り、2番目(右)のSELECTステートメントではなく、最初のSELECTステートメント(左)によって返される行を返します。
SELECT * from table1 where x,y,z
EXCEPT
SELECT * from table2 where a,b,c
PS:SELECTステートメントによって返される両方のテーブルのスキーマは一致する必要があります。
詳細については、チュートリアルポイントページをご覧ください。
/*
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列のテーブルがあり、それを別のテーブルと比較し、値が一致しないものを見つける必要がありました。このスクリプトは、正確なタプルを見つけるのに役立ちます。
私はあなたがあなたの場合にトリックを行うxSQL Data Compareを試してみるべきだと思います。たとえば、指定するとしましょう
SOURCE01.dbo.Customers as the **left table** and
TARGET01.dbo.Customers as the **right table**
テーブルを比較した後、比較結果で、このテーブルにないすべての行をTARGET01.dbo.Customersに挿入するSQLスクリプトを生成する左側のテーブルとの差分のみを同期するように指定できますが、 SOURCE01.dbo.Customersに存在します(重複のないUNION結果の達成)。お役に立てれば!
開示:xSQLに所属しています。