Operação de diferença simétrica no Transact-SQL?

10

Eu sempre soube sobre o UNIONoperador no SQL, mas só recentemente descobri que havia outros operadores de conjunto INTERSECTe EXCEPT. Não consegui encontrar um operador que faça o quarto operador de grande conjunto, a diferença simétrica (por exemplo, o oposto de INTERSECT.)

Parece que posso obter a saída desejada usando algo como

SELECT Field FROM A UNION SELECT Field FROM B 
EXCEPT
SELECT Field FROM A INTERSECT SELECT Field FROM B

(supondo que eu tenha a precedência correta) ou executando uma junção anti-completa:

SELECT A.Field, B.Field
FROM A
FULL JOIN B ON B.Id = A.Id
WHERE B.Id IS NULL OR A.Id IS NULL

Mas os dois parecem consultas bastante intensivas, especialmente em comparação com as outras três operações básicas do conjunto. Existe uma operação de diferença simétrica no SQL e simplesmente não consigo encontrá-la na documentação? Ou existe uma maneira "canônica" de implementá-lo no T-SQL?

KutuluMike
fonte
2
(a EXCEPT b) UNION ALL (b EXCEPT a);pode ser mais eficiente.
ypercubeᵀᴹ
@ypercube que faz 3 junções ou operações do tipo junção. Não consigo pensar em nenhum motivo para isso ser mais eficiente do que uma associação completa.
usr
@usr, na verdade, são duas operações de junção, e não 3. União Tudo é uma operação muito menos dispendiosa. Concordo que FULL JOINpode ser mais eficiente. Os testes podem revelar qual é o melhor. E, claro, se forem necessárias mais / diferentes colunas de cada tabela, minha solução não será facilmente expansível.
ypercubeᵀᴹ

Respostas:

3

Todos os operadores definidos são traduzidos para junções ou operadores do tipo junção. Você pode testemunhar isso no plano de consulta.

Por esse motivo, a junção externa completa que você possui é a mais eficiente que você pode fazer. Desconsiderando, é claro, a esperançosamente rara situação na qual o otimizador escolhe um plano ruim e uma reescrita passa a ter um desempenho melhor por sorte. Isso sempre pode acontecer.

usr
fonte
Isso faz sentido, no entanto, a razão de eu gostar de usar os operadores de conjunto é porque eles não criam "colunas extras" ... Eu posso fazer coisas assim SELECT Id FROM A WHERE <stuff> EXCEPT Select Id FROM A WHERE <other stuff>e obter uma única lista de Id. Não consigo descobrir como fazer isso com uma junção completa ... só preciso lidar com dois conjuntos de Idcolunas e uni-las novamente?
precisa saber é o seguinte
Você pode dizer ISNULL(a.Col, b.Col) AS Col. Embrulhe isso em uma tabela derivada ou CTE e você poderá usar o conjunto de resultados "dobrado" para mais operações nele. (Btw, eu concordo que o operador de diferença simétrica deva existir.)
usr
2
@MichaelEdenfield Por outro lado, e quando você deseja que outras colunas não estejam sendo usadas na comparação / distinção? Você pode fazer isso com uma junção, mas não com interseção / exceto. Então, em alguns casos, pude ver que a variação acabou se tornando muito mais complexa a longo prazo.
Aaron Bertrand
2

Eu acho que essa é uma solução muito boa. Ele usa uma união entre duas seleções com subconsultas Não existe. Melhor do que combinar Union e Except, porque você pode incluir campos que não coincidem na projeção.

SELECT  'A' TableName, FileType FROM KFX_Inventory I 
    WHERE Not Exists (Select Top 1 1 from KFX_FileType FT WHERE FT.FileType = I.FileType)
UNION ALL
SELECT  'B', FileType FROM KFX_FILEType FT 
    WHERE Not Exists (Select Top 1 1 from KFX_Inventory I WHERE FT.FileType = I.FileType)
Darrel Lee
fonte