Imagine que você tenha duas tabelas/consultas diferentes que deveriam ter/retornar dados idênticos. Você deseja verificar isso. Qual é uma maneira fácil de mostrar todas as linhas não correspondentes de cada tabela, como no exemplo abaixo, comparando todas as colunas? Suponha que haja 30 colunas nas tabelas, muitas das quais são NULLable.
Quando não há PK ou pode haver duplicatas por PK, juntar apenas colunas PK não é suficiente, e seria um desastre ter que fazer um FULL JOIN com 30 condições de junção que lidam adequadamente com NULLs, além de uma desagradável condição WHERE para excluir as linhas correspondentes.
Normalmente, é quando estou escrevendo uma nova consulta contra dados não apagados ou não totalmente compreendidos que o problema é pior e a probabilidade de um PK estar logicamente disponível é extremamente baixa. Eu crio duas maneiras diferentes de resolver o problema e depois comparo seus resultados, as diferenças destacando casos especiais nos dados que eu desconhecia.
O resultado precisa ficar assim:
Which Col1 Col2 Col3 ... Col30
------ ------ ------ ------ ------
TableA Cat 27 86 -- mismatch
TableB Cat 27 105 -- mismatch
TableB Cat 27 87 -- mismatch 2
TableA Cat 128 92 -- no corresponding row
TableB Lizard 83 NULL -- no corresponding row
Se [Col1, Col2]
acontecer de ser uma chave composta e ordenarmos por elas em nosso resultado final, podemos ver facilmente que A e B têm uma linha diferente que deve ser a mesma, e cada uma tem uma linha que não está na outra.
No exemplo acima, não é desejável ver a primeira linha duas vezes.
Aqui está DDL e DML para configurar tabelas e dados de amostra:
CREATE TABLE dbo.TableA (
Col1 varchar(10),
Col2 int,
Col3 int,
Col4 varchar(10),
Col5 varchar(10),
Col6 varchar(10),
Col7 varchar(10),
Col8 varchar(10),
Col9 varchar(10),
Col10 varchar(10),
Col11 varchar(10),
Col12 varchar(10),
Col13 varchar(10),
Col14 varchar(10),
Col15 varchar(10),
Col16 varchar(10),
Col17 varchar(10),
Col18 varchar(10),
Col19 varchar(10),
Col20 varchar(10),
Col21 varchar(10),
Col22 varchar(10),
Col23 varchar(10),
Col24 varchar(10),
Col25 varchar(10),
Col26 varchar(10),
Col27 varchar(10),
Col28 varchar(10),
Col29 varchar(10),
Col30 varchar(10)
);
CREATE TABLE dbo.TableB (
Col1 varchar(10),
Col2 int,
Col3 int,
Col4 varchar(10),
Col5 varchar(10),
Col6 varchar(10),
Col7 varchar(10),
Col8 varchar(10),
Col9 varchar(10),
Col10 varchar(10),
Col11 varchar(10),
Col12 varchar(10),
Col13 varchar(10),
Col14 varchar(10),
Col15 varchar(10),
Col16 varchar(10),
Col17 varchar(10),
Col18 varchar(10),
Col19 varchar(10),
Col20 varchar(10),
Col21 varchar(10),
Col22 varchar(10),
Col23 varchar(10),
Col24 varchar(10),
Col25 varchar(10),
Col26 varchar(10),
Col27 varchar(10),
Col28 varchar(10),
Col29 varchar(10),
Col30 varchar(10)
);
INSERT dbo.TableA (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30)
VALUES
('Cat', 27, 86, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Cat', 128, 92, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Porcupine', NULL, 42, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Tapir', NULL, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0')
;
INSERT dbo.TableB (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15, Col16, Col17, Col18, Col19, Col20, Col21, Col22, Col23, Col24, Col25, Col26, Col27, Col28, Col29, Col30)
VALUES
('Cat', 27, 105, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Cat', 27, 87, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Lizard', 83, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Porcupine', NULL, 42, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0'),
('Tapir', NULL, NULL, 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0');
Isso pode ser tratado usando EXCEPT e/ou INTERSECT. http://msdn.microsoft.com/en-us/library/ms188055.aspx
Primeiro localize todos os registros que estão na tabela1 que não estão na tabela 2 e, em seguida, localize todos os registros que estão na tabela 2 que não estão na tabela um.
Há, sem dúvida, uma maneira mais eficiente de fazer isso, mas é a primeira solução "rápida e suja" que me vem à cabeça. Além disso, não recomendo usar um caractere curinga *, mas serve aqui por brevidade.
Como alternativa, você pode usar um operador INTERSECT e excluir todos os resultados dele.
Você não precisa de 30 condições de junção para um
FULL OUTER JOIN
aqui.Você pode apenas Full Outer Join no PK, preservar linhas com pelo menos uma diferença
WHERE EXISTS (SELECT A.* EXCEPT SELECT B.*)
e usarCROSS APPLY (SELECT A.* UNION ALL SELECT B.*)
para desarticular os dois lados dasJOIN
linhas ed em linhas individuais.Dá
Ou uma versão lidando com os postes movidos.
Para tabelas com muitas colunas, ainda pode ser difícil identificar as colunas específicas que diferem. Para isso, você pode potencialmente usar o abaixo.
(embora apenas em tabelas relativamente pequenas, caso contrário, esse método provavelmente não terá desempenho adequado)
É fácil de realizar com uma ferramenta de terceiros, como o Data Compare, ou apenas no cliente. No contexto de procedimentos armazenados de teste de unidade, acabamos de escrever algum código C#.
Aqui está o código C# que estamos usando, citado em um artigo antigo: Feche essas brechas - Testando procedimentos armazenados
Aqui está uma maneira de mostrar o que foi solicitado: