私は2つのテーブルを持っているTableAと、TableB両方のテーブルを例えばカラムの同じフォーマットを有するTableAとTableB列を有しています
A B C D E F
ここで、AとBは主キーです。
SQLを記述して、TableAそれを確認する方法TableBして、同じ主キーを持つ、すべての列にまったく同じ値が含まれている。
これは、これら2つのテーブルのデータがまったく同じであることを意味します。
回答:
DBMSで使用されるSQLのフレーバーに応じて、「マイナス」または「除外」できるはずです。
select * from tableA
minus
select * from tableB
クエリが行を返さない場合、データはまったく同じです。
tableA余分な行がある場合は機能しません。あなたは、必要があるだろう(A EXCEPT B) INTERSECT (B EXCEPT A)、私は、これは沼地標準が参加するよりもはるかに少ない効率的であると思います。
関係演算子の使用:
SELECT * FROM TableA
UNION
SELECT * FROM TableB
EXCEPT
SELECT * FROM TableA
INTERSECT
SELECT * FROM TableB;
変更EXCEPTへMINUSます。
少し厄介な点:上記は演算子の優先順位に依存しています。これはSQL標準によれば実装に依存するため、YMMVです。これはSQLServerで機能し、優先順位は次のとおりです。
INTERSECTEXCEPTそしてUNION、左から右に評価しました。Dietbuddhaには良い答えがあります。MINUSまたはEXCEPTがない場合、1つのオプションは、テーブル間ですべての和集合を実行し、すべての列でグループ化して、すべてが2つあることを確認することです。
SELECT col1, col2, col3
FROM
(SELECT * FROM tableA
UNION ALL
SELECT * FROM tableB) data
GROUP BY col1, col2, col3
HAVING count(*)!=2
DISTINCT/GROUP BYが提案されます。そうしないと、TableAに2つのレコードがあり、TableBに0があり、HAVING条件を満たさない可能性があります。
ある日からスクリプトを取得し、各エントリがどのテーブルからのものかを示すようにスクリプトを変更しました。
DECLARE @table1 NVARCHAR(80)= 'table 1 name'
DECLARE @table2 NVARCHAR(80)= 'table 2 name'
DECLARE @sql NVARCHAR (1000)
SET @sql =
'
SELECT ''' + @table1 + ''' AS table_name,* FROM
(
SELECT * FROM ' + @table1 + '
EXCEPT
SELECT * FROM ' + @table2 + '
) x
UNION
SELECT ''' + @table2 + ''' AS table_name,* FROM
(
SELECT * FROM ' + @table2 + '
EXCEPT
SELECT * FROM ' + @table1 + '
) y
'
EXEC sp_executesql @stmt = @sql
完了するために、2つのテーブルを比較し、3つのエラーステータスを持つ同じテーブルに結果を与えるexceptメソッドを使用して保存されたproc、ADD、DEL、GAPテーブルは同じPKを持っている必要があります。
このように使用してくださいps_TableGap'tbl1 '、' Tbl2 '、' fld1、fld2、fld3 '、' fld4'fld5'fld6 '(オプション)
/****** Object: StoredProcedure [dbo].[ps_TableGap] Script Date: 10/03/2013 16:03:44 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Arnaud ALLAVENA
-- Create date: 03.10.2013
-- Description: Compare tables
-- =============================================
create PROCEDURE [dbo].[ps_TableGap]
-- Add the parameters for the stored procedure here
@Tbl1 as varchar(100),@Tbl2 as varchar(100),@Fld1 as varchar(1000), @Fld2 as varchar(1000)= ''
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--Variables
--@Tbl1 = table 1
--@Tbl2 = table 2
--@Fld1 = Fields to compare from table 1
--@Fld2 Fields to compare from table 2
Declare @SQL varchar(8000)= '' --SQL statements
Declare @nLoop int = 1 --loop counter
Declare @Pk varchar(1000)= '' --primary key(s)
Declare @Pk1 varchar(1000)= '' --first field of primary key
declare @strTmp varchar(50) = '' --returns value in Pk determination
declare @FldTmp varchar (1000) = '' --temporarily fields for alias calculation
--If @Fld2 empty we take @Fld1
--fields rules: fields to be compare must be in same order and type - always returns Gap
If @Fld2 = '' Set @Fld2 = @Fld1
--Change @Fld2 with Alias prefix xxx become _xxx
while charindex(',',@Fld2)>0
begin
Set @FldTmp = @FldTmp + (select substring(@Fld2,1,charindex(',',@Fld2)-1) + ' as _' + substring(@Fld2,1,charindex(',',@Fld2)-1) + ',')
Set @Fld2 = (select ltrim(right(@Fld2,len(@Fld2)-charindex(',',@Fld2))))
end
Set @FldTmp = @FldTmp + @Fld2 + ' as _' + @Fld2
Set @Fld2 = @FldTmp
--Determinate primary key jointure
--rule: same pk in both tables
Set @nLoop = 1
Set @SQL = 'Declare crsr cursor for select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = '''
+ @Tbl1 + ''' or TABLE_SCHEMA + ''.'' + TABLE_NAME = ''' + @Tbl1 + ''' or TABLE_CATALOG + ''.'' + TABLE_SCHEMA + ''.'' + TABLE_NAME = ''' + @Tbl1
+ ''' order by ORDINAL_POSITION'
exec(@SQL)
open crsr
fetch next from crsr into @strTmp
while @@fetch_status = 0
begin
if @nLoop = 1
begin
Set @Pk = 's.' + @strTmp + ' = b._' + @strTmp
Set @Pk1 = @strTmp
set @nLoop = @nLoop + 1
end
Else
Set @Pk = @Pk + ' and s.' + @strTmp + ' = b._' + @strTmp
fetch next from crsr into @strTmp
end
close crsr
deallocate crsr
--SQL statement build
set @SQL = 'select case when s.' + @Pk1 + ' is null then ''Del'' when b._' + @Pk1 + ' is null then ''Add'' else ''Gap'' end as TypErr, '''
set @SQL = @SQL + @Tbl1 +''' as Tbl1, s.*, ''' + @Tbl2 +''' as Tbl2 ,b.* from (Select ' + @Fld1 + ' from ' + @Tbl1
set @SQL = @SQL + ' EXCEPT SELECT ' + @Fld2 + ' from ' + @Tbl2 + ')s full join (Select ' + @Fld2 + ' from ' + @Tbl2
set @SQL = @SQL + ' EXCEPT SELECT ' + @Fld1 + ' from ' + @Tbl1 +')b on '+ @Pk
--Run SQL statement
Exec(@SQL)
END
出典:NATURAL FULL JOINを使用して、LukasEderによるSQLの2つのテーブルを比較します
使用の巧妙なアプローチ NATURAL FULL JOIN2つのテーブル間で同じ/異なる行を検出するためする。
例1-ステータスフラグ:
SELECT t1.*, t2.*, CASE WHEN t1 IS NULL OR t2 IS NULL THEN 'Not equal' ELSE 'Equal' END
FROM t1
NATURAL FULL JOIN t2;
例2-行のフィルタリング
SELECT *
FROM (SELECT 't1' AS t1, t1.* FROM t1) t1
NATURAL FULL JOIN (SELECT 't2' AS t2, t2.* FROM t2) t2
WHERE t1 IS NULL OR t2 IS NULL -- show differences
--WHERE t1 IS NOT NULL AND t2 IS NOT NULL -- show the same
Oracleですべて挿入と完全外部結合を組み合わせて使用すると、2つのテーブルの違いを見つけることができます。SQLでは、完全外部結合を介して違いを抽出できますが、すべて/最初の挿入がSQLに存在しないようです!したがって、代わりに次のクエリを使用する必要があります。
select * from A
full outer join B on
A.pk=B.pk
where A.field1!=B.field1
or A.field2!=B.field2 or A.field3!=B.field3 or A.field4!=B.field4
--and A.Date==Date1
where句で「OR」を使用することは推奨されておらず、通常はパフォーマンスが低下しますが、テーブルが大きくない場合は、上記のクエリを使用できます。上記のクエリの結果がある場合、それはフィールド1、2、3、4の比較に基づく2つのテーブルの違いです。クエリのパフォーマンスを向上させるために、日付でフィルタリングすることもできます(コメント部分を確認してください)
SELECT unnest(ARRAY[1,2,2,3,3])
EXCEPT
SELECT unnest(ARRAY[1,1,2,3,3])
UNION
SELECT unnest(ARRAY[1,1,2,3,3])
EXCEPT
SELECT unnest(ARRAY[1,2,2,3,3])
結果はnullですが、ソースが異なります。
だが:
(
SELECT unnest(ARRAY[1,2,2,3])
EXCEPT ALL
SELECT unnest(ARRAY[2,1,2,3])
)
UNION
(
SELECT unnest(ARRAY[2,1,2,3])
EXCEPT ALL
SELECT unnest(ARRAY[1,2,2,3])
)
動作します。
私はSQLServerでこれと同じ問題を抱えており、プロセスを自動化するためにこのT-SQLスクリプトを作成しました(実際、これは骨抜きにされたバージョンであり、レポートを簡単にするためにすべての差分を1つのテーブルに書き込みました)。
「MyTable」と「MyOtherTable」を比較するテーブルの名前に更新します。
DECLARE @ColName varchar(100)
DECLARE @Table1 varchar(100) = 'MyTable'
DECLARE @Table2 varchar(100) = 'MyOtherTable'
IF (OBJECT_ID('tempdb..#col') IS NOT NULL) DROP TABLE #col
SELECT IDENTITY(INT, 1, 1) RowNum , c.name
INTO #col
FROM SYS.Objects o
JOIN SYS.columns c on o.object_id = c.object_id
WHERE o.name = @Table1 AND NOT c.Name IN ('List','Columns','YouWantToIgnore')
DECLARE @Counter INT = (SELECT MAX(RowNum) FROM #col)
WHILE @Counter > 0
BEGIN
SET @ColName = (SELECT name FROM #Col WHERE RowNum= @Counter)
EXEC ('SELECT t1.Identifier
,t1.'+@ColName+' AS '+@Table1+@ColName+'
,t2.'+@ColName+' AS '+@Table2+@ColName+'
FROM '+@Table1+' t1
LEFT JOIN '+@Table2+' t2 ON t1.Identifier = t2.Identifier
WHERE t1.'+@ColName+' <> t2.'+@ColName)
SET @Counter = @Counter - 1
END
これは、OracleからSQLServerに移植したかなり厄介なビューの結果を比較するために作成しました。これにより、一時テーブルのペア#DataVariancesと#SchemaVariancesが作成され、テーブル内のデータとテーブル自体のスキーマが異なります(ご想像のとおり)。
両方のテーブルに主キーが必要ですが、ソーステーブルに主キーがない場合は、ID列を使用してtempdbにドロップできます。
declare @TableA_ThreePartName nvarchar(max) = ''
declare @TableB_ThreePartName nvarchar(max) = ''
declare @KeyName nvarchar(max) = ''
/***********************************************************************************************
Script to compare two tables and return differneces in schema and data.
Author: Devin Lamothe 2017-08-11
***********************************************************************************************/
set nocount on
-- Split three part name into database/schema/table
declare @Database_A nvarchar(max) = (
select left(@TableA_ThreePartName,charindex('.',@TableA_ThreePartName) - 1))
declare @Table_A nvarchar(max) = (
select right(@TableA_ThreePartName,len(@TableA_ThreePartName) - charindex('.',@TableA_ThreePartName,len(@Database_A) + 2)))
declare @Schema_A nvarchar(max) = (
select replace(replace(@TableA_ThreePartName,@Database_A + '.',''),'.' + @Table_A,''))
declare @Database_B nvarchar(max) = (
select left(@TableB_ThreePartName,charindex('.',@TableB_ThreePartName) - 1))
declare @Table_B nvarchar(max) = (
select right(@TableB_ThreePartName,len(@TableB_ThreePartName) - charindex('.',@TableB_ThreePartName,len(@Database_B) + 2)))
declare @Schema_B nvarchar(max) = (
select replace(replace(@TableB_ThreePartName,@Database_B + '.',''),'.' + @Table_B,''))
-- Get schema for both tables
declare @GetTableADetails nvarchar(max) = '
use [' + @Database_A +']
select COLUMN_NAME
, DATA_TYPE
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = ''' + @Table_A + '''
and TABLE_SCHEMA = ''' + @Schema_A + '''
'
create table #Table_A_Details (
ColumnName nvarchar(max)
, DataType nvarchar(max)
)
insert into #Table_A_Details
exec (@GetTableADetails)
declare @GetTableBDetails nvarchar(max) = '
use [' + @Database_B +']
select COLUMN_NAME
, DATA_TYPE
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = ''' + @Table_B + '''
and TABLE_SCHEMA = ''' + @Schema_B + '''
'
create table #Table_B_Details (
ColumnName nvarchar(max)
, DataType nvarchar(max)
)
insert into #Table_B_Details
exec (@GetTableBDetails)
-- Get differences in table schema
select ROW_NUMBER() over (order by
a.ColumnName
, b.ColumnName) as RowKey
, a.ColumnName as A_ColumnName
, a.DataType as A_DataType
, b.ColumnName as B_ColumnName
, b.DataType as B_DataType
into #FieldList
from #Table_A_Details a
full outer join #Table_B_Details b
on a.ColumnName = b.ColumnName
where a.ColumnName is null
or b.ColumnName is null
or a.DataType <> b.DataType
drop table #Table_A_Details
drop table #Table_B_Details
select coalesce(A_ColumnName,B_ColumnName) as ColumnName
, A_DataType
, B_DataType
into #SchemaVariances
from #FieldList
-- Get differences in table data
declare @LastColumn int = (select max(RowKey) from #FieldList)
declare @RowNumber int = 1
declare @ThisField nvarchar(max)
declare @TestSql nvarchar(max)
create table #DataVariances (
TableKey nvarchar(max)
, FieldName nvarchar(max)
, TableA_Value nvarchar(max)
, TableB_Value nvarchar(max)
)
delete from #FieldList where A_DataType in ('varbinary','image') or B_DataType in ('varbinary','image')
while @RowNumber <= @LastColumn begin
set @TestSql = '
select coalesce(a.[' + @KeyName + '],b.[' + @KeyName + ']) as TableKey
, ''' + @ThisField + ''' as FieldName
, a.[' + @ThisField + '] as [TableA_Value]
, b.[' + @ThisField + '] as [TableB_Value]
from [' + @Database_A + '].[' + @Schema_A + '].[' + @Table_A + '] a
inner join [' + @Database_B + '].[' + @Schema_B + '].[' + @Table_B + '] b
on a.[' + @KeyName + '] = b.[' + @KeyName + ']
where ltrim(rtrim(a.[' + @ThisField + '])) <> ltrim(rtrim(b.[' + @ThisField + ']))
or (a.[' + @ThisField + '] is null and b.[' + @ThisField + '] is not null)
or (a.[' + @ThisField + '] is not null and b.[' + @ThisField + '] is null)
'
insert into #DataVariances
exec (@TestSql)
set @RowNumber = @RowNumber + 1
set @ThisField = (select coalesce(A_ColumnName,B_ColumnName) from #FieldList a where RowKey = @RowNumber)
end
drop table #FieldList
print 'Query complete. Select from #DataVariances to verify data integrity or #SchemaVariances to verify schemas match. Data types varbinary and image are not checked.'
ほとんどの回答は、カミルによって提起された問題を無視しているようです。(ここで、テーブルには同じ行が含まれますが、各テーブルで異なる行が繰り返されます。)残念ながら、私はOracleにいるため、彼のソリューションを使用できません。私が思いついた最高のものは次のとおりです。
SELECT * FROM
(
SELECT column1, column2, ..., COUNT(*) AS the_count
FROM tableA
GROUP BY column1, column2, ...
MINUS
SELECT column1, column2, ..., COUNT(*) AS the_count
FROM tableB
GROUP BY column1, column2, ...
)
UNION ALL
(
SELECT column1, column2, ..., COUNT(*) AS the_count
FROM tableB
GROUP BY column1, column2, ...
MINUS
SELECT column1, column2, ..., COUNT(*) AS the_count
FROM tableA
GROUP BY column1, column2, ...
)
T1(PK、A、B)とT2(PK、A、B)を比較します。
まず、主キーセットを比較して、いずれかの側で欠落しているキー値を探します。
SELECT T1.*, T2.* FROM T1 FULL OUTER JOIN T2 ON T1.PK=T2.PK WHERE T1.PK IS NULL OR T2.PK IS NULL;
次に、すべての値の不一致をリストします。
SELECT T1.PK, 'A' AS columnName, T1.A AS leftValue, T2.A AS rightValue FROM T1 JOIN T2 ON T1.PK=T2.PK WHERE COALESCE(T1.A,0) != COALESCE(T2.A,0)
UNION ALL
SELECT T1.PK, 'B' AS columnName, T1.B AS leftValue, T2.B AS rightValue FROM T1 JOIN T2 ON T1.PK=T2.PK WHERE COALESCE(T1.B,0) != COALESCE(T2.B,0)
AとBは同じタイプである必要があります。INFORMATIONSCHEMAを使用してSELECTを生成できます。COALESCEには、ISNULLの結果も含めることを忘れないでください。FULL OUTER JOINおよびCOALESCE(T1.PK、0)= COALESCE(T2.PK、0)を使用することもできます。
たとえば、varchar型の列の場合:
SELECT concat('SELECT T1.PK, ''', COLUMN_NAME, ''' AS columnName, T1.', COLUMN_NAME, ' AS leftValue, T2.', COLUMN_NAME, ' AS rightValue FROM T1 JOIN T2 ON T1.PK=T2.PK WHERE COALESCE(T1.',COLUMN_NAME, ',0)!=COALESCE(T2.', COLUMN_NAME, ',0)')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='T1' AND DATA_TYPE IN ('nvarchar','varchar');
以下の簡単なクエリを使用して、DB2テーブルの2つのテーブルのデータを比較できます。
ステップ1:-スキーマ(S)のテーブル(T1)から比較する必要があるすべての列を選択します
SELECT T1.col1,T1.col3,T1.col5 from S.T1
ステップ2:-2つのテーブルを比較するために「マイナス」キーワードを使用します。
ステップ3:-スキーマ(S)のテーブル(T2)から比較する必要があるすべての列を選択します
SELECT T2.col1,T2.col3,T2.col5 from S.T1
最終結果:
SELECT T1.col1,T1.col3,T1.col5 from S.T1
MINUS
SELECT T2.col1,T2.col3,T2.col5 from S.T1;
クエリが行を返さない場合、データはまったく同じです。
Dietbuddha&IanMcによる回答に基づく代替の拡張クエリ。クエリには、行が存在する場所と欠落している場所をわかりやすく示すための説明が含まれています。(注:SQL Serverの場合)
(
select 'InTableA_NoMatchInTableB' as Msg, * from tableA
except
select 'InTableA_NoMatchInTableB' , * from tableB
)
union all
(
select 'InTableB_NoMatchInTableA' as Msg, * from tableB
except
select 'InTableB_NNoMatchInTableA' ,* from tableA
)
SELECT *
FROM TABLE A
WHERE NOT EXISTS (SELECT 'X'
FROM TABLE B
WHERE B.KEYFIELD1 = A.KEYFIELD1
AND B.KEYFIELD2 = A.KEYFIELD2
AND B.KEYFIELD3 = A.KEYFIELD3)
;
「X」は任意の値です。
テーブルを切り替えて、さまざまな不一致を確認します。
テーブルのキーフィールドを必ず結合してください。
または、2つのselectステートメントでMINUS演算子を使用するだけですが、MINUSはOracleでのみ機能します。