Eu tenho 2 tabelas TableA
e TableB
que têm o mesmo formato de coluna, por exemplo ambas as tabelas TableA
e TableB
têm colunas
A B C D E F
onde A e B são as chaves primárias.
Como escrever SQL para verificar se se TableA
e TableB
isso têm as mesmas chaves primárias contém exatamente o mesmo valor em todas as colunas.
Isso significa que essas duas tabelas têm exatamente os mesmos dados.
tableA
tiver linhas extras. Você precisaria,(A EXCEPT B) INTERSECT (B EXCEPT A)
eu acho que isso seria muito menos eficiente do que uma junção padrão de bog.Usando operadores relacionais:
SELECT * FROM TableA UNION SELECT * FROM TableB EXCEPT SELECT * FROM TableA INTERSECT SELECT * FROM TableB;
Mude
EXCEPT
paraMINUS
para Oracle.Ponto um pouco exigente: o acima depende da precedência do operador, que de acordo com o padrão SQL é dependente da implementação, portanto, YMMV. Funciona para SQL Server, para o qual a precedência é:
INTERSECT
EXCEPT
eUNION
avaliados da esquerda para a direita.fonte
dietbuddha tem uma boa resposta. Nos casos em que você não tem MENUS ou EXCEPT, uma opção é fazer uma união entre todas as tabelas, agrupar com todas as colunas e garantir que haja dois de tudo:
SELECT col1, col2, col3 FROM (SELECT * FROM tableA UNION ALL SELECT * FROM tableB) data GROUP BY col1, col2, col3 HAVING count(*)!=2
fonte
DISTINCT
/GROUP BY
é sugerido para as subconsultas na união, para garantir que haja apenas um registro por tabela. Caso contrário, a Tabela A poderia ter 2 registros e a Tabela B poderia ter 0 e não atender à condição HAVING.SELECT c.ID FROM clients c WHERE EXISTS(SELECT c2.ID FROM clients2 c2 WHERE c2.ID = c.ID);
Retornará todos os IDs que são iguais em ambas as tabelas. Para obter as diferenças, altere EXISTS para NOT EXISTS.
fonte
Pegando o script de um dia quando, eu o modifiquei para mostrar também de qual tabela vem cada entrada.
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
fonte
apenas para completar, um proc armazenado usando o método except para comparar 2 tabelas e dar resultado na mesma tabela com 3 status de erros, ADD, DEL, tabela GAP deve ter o mesmo PK, você declara as 2 tabelas e campos para comparar de 1 ou ambas as tabelas
Basta usar como este ps_TableGap 'tbl1', 'Tbl2', 'fld1, fld2, fld3', 'fld4'fld5'fld6' (opcional)
/****** 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
fonte
Fonte: Use NATURAL FULL JOIN para comparar duas tabelas em SQL de Lukas Eder
Abordagem inteligente de uso
NATURAL FULL JOIN
para detectar as mesmas / diferentes linhas entre duas tabelas.Exemplo 1 - sinalizador de status:
SELECT t1.*, t2.*, CASE WHEN t1 IS NULL OR t2 IS NULL THEN 'Not equal' ELSE 'Equal' END FROM t1 NATURAL FULL JOIN t2;
Exemplo 2 - filtragem de linhas
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 <> demonstração de violino
fonte
Aprimoramento da resposta de dietbuddha ...
select * from ( select * from tableA minus select * from tableB ) union all select * from ( select * from tableB minus select * from tableA )
fonte
Você pode encontrar diferenças de 2 tabelas usando a combinação de inserir tudo e junção externa completa no Oracle. No sql você pode extrair as diferenças via full outer join, mas parece que insert all / first não existe no sql! Portanto, você deve usar a seguinte consulta:
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
Embora o uso de 'OR' na cláusula where não seja recomendado e geralmente resulte em desempenho inferior, você ainda pode usar a consulta acima se suas tabelas não forem massivas. Se houver algum resultado para a consulta acima, é exatamente a diferença de 2 tabelas baseadas na comparação dos campos 1,2,3,4. Para melhorar o desempenho da consulta, você também pode filtrá-la por data (verifique a parte comentada)
fonte
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])
O resultado é nulo, mas as fontes são diferentes!
Mas:
( 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]) )
trabalho.
fonte
Eu tive esse mesmo problema no SQL Server e escrevi este script T-SQL para automatizar o processo (na verdade, esta é a versão diluída, o meu escreveu todas as diferenças em uma única tabela para facilitar o relatório).
Atualize 'MyTable' e 'MyOtherTable' para os nomes das tabelas que deseja comparar.
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
fonte
Escrevi isso para comparar os resultados de uma visão bastante desagradável que transferi do Oracle para o SQL Server. Ele cria um par de tabelas temporárias, #DataVariances e #SchemaVariances, com diferenças (você adivinhou) nos dados nas tabelas e no esquema das próprias tabelas.
Requer que ambas as tabelas tenham uma chave primária, mas você pode soltá-la em tempdb com uma coluna de identidade se as tabelas de origem não tiverem uma.
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.'
fonte
A maioria das respostas parece ignorar a questão levantada por Kamil. (É aí que as tabelas contêm linhas idênticas, mas diferentes são repetidas em cada tabela.) Infelizmente, não estou conseguindo usar a solução dele, porque estou no Oracle. O melhor que consegui sugerir é:
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, ... )
fonte
Para comparar T1 (PK, A, B) e T2 (PK, A, B).
Primeiro compare os conjuntos de chaves primárias para procurar valores de chave ausentes em qualquer um dos lados:
SELECT T1.*, T2.* FROM T1 FULL OUTER JOIN T2 ON T1.PK=T2.PK WHERE T1.PK IS NULL OR T2.PK IS NULL;
Em seguida, liste todos os valores incompatíveis:
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 e B devem ser do mesmo tipo. Você pode usar o ESQUEMA DE INFORMAÇÕES para gerar o SELECT. Não se esqueça de COALESCE para incluir também os resultados IS NULL. Você também pode usar FULL OUTER JOIN e COALESCE (T1.PK, 0) = COALESCE (T2.PK, 0).
Por exemplo, para colunas do tipo 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');
fonte
Podemos comparar os dados de duas tabelas de tabelas do DB2 usando a consulta simples abaixo,
Etapa 1: - Selecione quais colunas precisamos comparar da tabela (T1) do esquema (S)
SELECT T1.col1,T1.col3,T1.col5 from S.T1
Passo 2: - Use a palavra-chave 'Menos' para comparar 2 tabelas.
Etapa 3: - Selecione quais colunas precisamos comparar da tabela (T2) do esquema (S)
SELECT T2.col1,T2.col3,T2.col5 from S.T1
Resultado final:
SELECT T1.col1,T1.col3,T1.col5 from S.T1 MINUS SELECT T2.col1,T2.col3,T2.col5 from S.T1;
Se a consulta não retornar nenhuma linha, os dados serão exatamente os mesmos.
fonte
No MySQL, onde "menos" não é suportado, e levando em consideração o desempenho, este é um
query: SELECT t1.id, t1.id FROM t1 inner join t2 using (id) where concat(t1.C, t1.D, ...)<>concat(t2.C, t2.D, ...)
fonte
Uma consulta alternativa e aprimorada com base na resposta de dietbuddha & IanMc. A consulta inclui uma descrição para mostrar de maneira útil onde as linhas existem e estão faltando. (NB: para 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 )
fonte
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' é qualquer valor.
Troque as tabelas para ver as diferentes discrepâncias.
Certifique-se de juntar os campos-chave em suas tabelas.
Ou apenas use o operador MINUS com 2 instruções de seleção, no entanto, MINUS só pode funcionar no Oracle.
fonte