Operación de diferencia simétrica en Transact-SQL?

10

Siempre he sabido sobre el UNIONoperador en SQL, pero solo recientemente descubrí que había otros operadores de conjuntos, INTERSECTy EXCEPT. No he podido encontrar un operador que haga el cuarto operador de conjunto grande, la diferencia simétrica (por ejemplo, lo opuesto a INTERSECT).

Parece que puedo obtener el resultado deseado usando algo como

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

(suponiendo que tengo la prioridad correcta), o haciendo un anti-full-join:

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

Pero ambas parecen consultas bastante intensivas, especialmente en comparación con las otras tres operaciones básicas de configuración. ¿Existe una operación de diferencia simétrica en SQL y simplemente no puedo encontrarla en la documentación? ¿O hay una forma "canónica" de implementarlo en T-SQL?

KutuluMike
fuente
2
(a EXCEPT b) UNION ALL (b EXCEPT a);Podría ser más eficiente.
ypercubeᵀᴹ
@ypercube que realiza 3 uniones u operaciones similares a uniones. No puedo pensar en ninguna razón por la que esto sea más eficiente que una unión completa.
usr
@usr en realidad son 2 operaciones de unión, no 3. Union All es una operación mucho menos costosa. Estoy de acuerdo en que FULL JOINpuede ser más eficiente. Las pruebas pueden revelar cuál es el mejor. Y, por supuesto, si se necesitan más / diferentes columnas de cada tabla, mi solución no es fácilmente expandible.
ypercubeᵀᴹ

Respuestas:

3

Todos los operadores de conjunto se traducen en uniones u operadores similares. Puede presenciar eso en el plan de consulta.

Por esa razón, la combinación externa completa que tiene allí es la más eficiente que puede hacer. Sin tener en cuenta, por supuesto, la situación con suerte rara en la que el optimizador elige un mal plan y una reescritura tiene un mejor desempeño por suerte. Esto siempre puede suceder.

usr
fuente
Sin embargo, eso tiene sentido, la razón por la que me gusta usar los operadores de conjuntos es porque no crean "columnas adicionales" ... Puedo hacer cosas como SELECT Id FROM A WHERE <stuff> EXCEPT Select Id FROM A WHERE <other stuff>y obtener una sola lista de Id. No puedo entender cómo hacer eso con una unión completa ... ¿solo necesito lidiar con tener dos conjuntos de Idcolumnas y unirlas nuevamente?
KutuluMike
Se puede decir ISNULL(a.Col, b.Col) AS Col. Envuelva eso en una tabla derivada o CTE y puede usar el conjunto de resultados "plegado" para una mayor operación en él. (Por cierto, estoy de acuerdo en que debería existir el operador de diferencia simétrica)
Usr
2
@MichaelEdenfield Por otro lado, ¿qué pasa cuando quieres otras columnas que no se usan en la comparación / distinción? Puede hacerlo con una unión pero no con intersección / excepto. Así que pude ver en algunos casos que la variación en realidad termina siendo mucho más compleja a largo plazo.
Aaron Bertrand
2

Creo que esta es una muy buena solución. Utiliza una unión entre dos selecciones con subconsultas No existe. Mejor que combinar Unión y Excepto porque puede incluir campos que no coinciden en la proyección.

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
fuente