Mam 2 tabele TableA
i TableB
które mają ten sam format kolumny na przykład obie tabele TableA
i TableB
mieć kolumny
A B C D E F
gdzie A i B to klucze podstawowe.
Jak napisać SQL, aby sprawdzić, czy jeśli TableA
i TableB
które mają te same klucze podstawowe, zawierają dokładnie tę samą wartość we wszystkich kolumnach.
Oznacza to, że te dwie tabele zawierają dokładnie te same dane.
tableA
ma dodatkowe wiersze. Potrzebowałbyś,(A EXCEPT B) INTERSECT (B EXCEPT A)
myślę, że byłoby to znacznie mniej wydajne niż standardowe złączenie bog.Korzystanie z operatorów relacyjnych:
SELECT * FROM TableA UNION SELECT * FROM TableB EXCEPT SELECT * FROM TableA INTERSECT SELECT * FROM TableB;
Zmień
EXCEPT
naMINUS
dla Oracle.Nieco wybredna uwaga: powyższe opiera się na pierwszeństwie operatorów, które zgodnie ze standardem SQL jest zależne od implementacji, czyli YMMV. Działa na SQL Server, dla którego priorytetem jest:
INTERSECT
EXCEPT
iUNION
oceniane od lewej do prawej.źródło
dietbuddha ma miłą odpowiedź. W przypadkach, w których nie masz MINUS lub EXCEPT, jedną z opcji jest wykonanie unii wszystkich tabel, pogrupowanie według wszystkich kolumn i upewnienie się, że są dwie z nich:
SELECT col1, col2, col3 FROM (SELECT * FROM tableA UNION ALL SELECT * FROM tableB) data GROUP BY col1, col2, col3 HAVING count(*)!=2
źródło
DISTINCT
/GROUP BY
, aby upewnić się, że w tabeli jest tylko jeden rekord. W przeciwnym razie Tabela A mogłaby mieć 2 rekordy, a Tabela B mogłaby mieć 0 i nie spełniać warunku HAVING.SELECT c.ID FROM clients c WHERE EXISTS(SELECT c2.ID FROM clients2 c2 WHERE c2.ID = c.ID);
Zwróci wszystkie identyfikatory, które są takie same w obu tabelach. Aby uzyskać różnice, zmień ISTNIEJE na NIE ISTNIEJE.
źródło
Biorąc skrypt z jednego dnia, zmodyfikowałem go, aby pokazać również, z której tabeli pochodzi każdy wpis.
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
źródło
tylko do zakończenia, proc zapisany przy użyciu metody oprócz porównania 2 tabel i podania wyniku w tej samej tabeli ze statusem 3 błędów, ADD, DEL, GAP tabela musi mieć ten sam PK, deklarujesz 2 tabele i pola do porównania 1 lub obu tabel
Po prostu użyj w ten sposób ps_TableGap 'tbl1', 'Tbl2', 'fld1, fld2, fld3', 'fld4'fld5'fld6' (opcjonalnie)
/****** 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
źródło
Źródło: użyj NATURAL FULL JOIN, aby porównać dwie tabele w języku SQL autorstwa Lukasa Edera
Sprytne podejście do używania
NATURAL FULL JOIN
do wykrywania tych samych / różnych wierszy między dwiema tabelami.Przykład 1 - flaga stanu:
SELECT t1.*, t2.*, CASE WHEN t1 IS NULL OR t2 IS NULL THEN 'Not equal' ELSE 'Equal' END FROM t1 NATURAL FULL JOIN t2;
Przykład 2 - filtrowanie wierszy
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
db <> fiddle demo
źródło
Wzmocnienie odpowiedzi Dietbuddha ...
select * from ( select * from tableA minus select * from tableB ) union all select * from ( select * from tableB minus select * from tableA )
źródło
Możesz znaleźć różnice między 2 tabelami, używając kombinacji wstawiania wszystkiego i pełnego sprzężenia zewnętrznego w Oracle. W sql możesz wyodrębnić różnice przez pełne zewnętrzne sprzężenie, ale wygląda na to, że wstaw wszystko / pierwsze nie istnieje w sql! Dlatego zamiast tego należy użyć następującego zapytania:
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
Chociaż użycie „OR” w klauzuli where nie jest zalecane i zwykle skutkuje niższą wydajnością, nadal możesz użyć powyższego zapytania, jeśli twoje tabele nie są ogromne. Jeśli istnieje jakikolwiek wynik dla powyższego zapytania, to właśnie różnice między 2 tabelami na podstawie porównania pól 1,2,3,4. Aby poprawić wydajność zapytania, możesz również filtrować je według daty (sprawdź skomentowaną część)
źródło
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])
Wynik jest pusty, ale źródła są różne!
Ale:
( 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]) )
Pracuje.
źródło
Miałem ten sam problem w SQL Server i napisałem ten skrypt T-SQL, aby zautomatyzować proces (w rzeczywistości jest to rozwodniona wersja, moja zapisała wszystkie różnice w jednej tabeli, aby ułatwić raportowanie).
Zaktualizuj „MyTable” i „MyOtherTable” do nazw tabel, które chcesz porównać.
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
źródło
Napisałem to, aby porównać wyniki dość nieprzyjemnego widoku, który przeniosłem z Oracle do SQL Server. Tworzy parę tabel tymczasowych, #DataVariances i #SchemaVariances, z różnicami w (zgadłeś) danych w tabelach i schemacie samych tabel.
Wymaga, aby obie tabele miały klucz podstawowy, ale można upuścić go do tempdb z kolumną tożsamości, jeśli tabele źródłowe go nie mają.
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.'
źródło
Większość odpowiedzi zdaje się ignorować kwestię poruszoną przez Kamila. (To tam tabele zawierają identyczne wiersze, ale różne są powtarzane w każdej tabeli.) Niestety nie jestem w stanie skorzystać z jego rozwiązania, ponieważ jestem w Oracle. Najlepsze, co udało mi się wymyślić, to:
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, ... )
źródło
Aby porównać T1 (PK, A, B) i T2 (PK, A, B).
Najpierw porównaj zestawy kluczy podstawowych, aby znaleźć brakujące wartości kluczy po obu stronach:
SELECT T1.*, T2.* FROM T1 FULL OUTER JOIN T2 ON T1.PK=T2.PK WHERE T1.PK IS NULL OR T2.PK IS NULL;
Następnie wypisz wszystkie niezgodności wartości:
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 i B muszą być tego samego typu. Możesz użyć SCHEMATU INFORMACJI, aby wygenerować SELECT. Nie zapomnij, aby COALESCE zawierał również wyniki IS NULL. Możesz również użyć FULL OUTER JOIN i COALESCE (T1.PK, 0) = COALESCE (T2.PK, 0).
Na przykład dla kolumn typu 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');
źródło
Możemy porównać dane z dwóch tabel tabel DB2 za pomocą poniższego prostego zapytania,
Krok 1: - Wybierz wszystkie kolumny, które musimy porównać z tabeli (T1) schematu (S)
SELECT T1.col1,T1.col3,T1.col5 from S.T1
Krok 2: - Użyj słowa kluczowego „Minus” do porównania 2 tabel.
Krok 3: - Wybierz wszystkie kolumny, które musimy porównać z tabeli (T2) schematu (S)
SELECT T2.col1,T2.col3,T2.col5 from S.T1
Wynik END:
SELECT T1.col1,T1.col3,T1.col5 from S.T1 MINUS SELECT T2.col1,T2.col3,T2.col5 from S.T1;
Jeśli zapytanie nie zwraca żadnych wierszy, dane są dokładnie takie same.
źródło
W MySQL, gdzie „minus” nie jest obsługiwany, a biorąc pod uwagę wydajność, jest to szybkie
query: SELECT t1.id, t1.id FROM t1 inner join t2 using (id) where concat(t1.C, t1.D, ...)<>concat(t2.C, t2.D, ...)
źródło
Alternatywne, rozszerzone zapytanie oparte na odpowiedzi od dietbuddha i IanMc. Zapytanie zawiera opis, który pomaga pokazać, gdzie istnieją wiersze, a gdzie ich brakuje. (Uwaga: dla 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 )
źródło
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” to dowolna wartość.
Przełącz tabele, aby zobaczyć różne rozbieżności.
Pamiętaj, aby połączyć kluczowe pola w swoich tabelach.
Lub po prostu użyj operatora MINUS z 2 instrukcjami Select, jednak MINUS może działać tylko w Oracle.
źródło