Transact-SQL中的对称差异运算?


10

我一直都知道UNIONSQL中的运算符,但是直到最近才发现还有其他集合运算符,INTERSECTEXCEPT。我还没有找到执行第四个大集合运算符的运算符,即对称差(例如的反函数INTERSECT)。

看起来我可以通过使用类似的东西来获得所需的输出

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

(假设我的优先级正确),或通过执行反全联接:

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

但是,这两个查询看起来都很密集,特别是与其他三个基本集合操作相比。SQL中是否存在对称差异操作,而我只是在文档中找不到它?还是有在T-SQL中实现“规范”的方式?


2
(a EXCEPT b) UNION ALL (b EXCEPT a);可能会更有效率。
ypercubeᵀᴹ

@ypercube执行3个join或类似join的操作。我想不出任何理由比完全加入更有效率。
usr

@usr实际上是2个类似join的操作,而不是3个。Union All的开销要小得多。我同意这FULL JOIN可能会更有效率。测试可以揭示最好的。当然,如果需要每个表中的更多/不同的列,则我的解决方案不容易扩展。
ypercubeᵀᴹ

Answers:


3

所有集合运算符都转换为联接或类似联接的运算符。您可以在查询计划中见证这一点。

因此,您可以执行的最高效的外部联接。当然,不管这种希望极少发生的情况,在这种情况下,优化器会选择错误的计划,而改写恰好能带来更好的运气。这总是可能发生。


但这是有道理的,我之所以喜欢使用set运算符是因为它们不创建“额外的列” ...我可以做类似的事情SELECT Id FROM A WHERE <stuff> EXCEPT Select Id FROM A WHERE <other stuff>并获得的单个列表Id。我不知道如何通过完全连接来实现这一点...我是否只需要处理两组Id列并将它们自己合并在一起?
KutuluMike 2014年

你可以说ISNULL(a.Col, b.Col) AS Col。将其包装在派生表或CTE中,然后可以使用“折叠”结果集对其进行进一步操作。(顺便说一句,我同意对称差分算子应该存在。)
usr

2
@MichaelEdenfield另一方面,当您希望在比较/区别中不使用其他列时该怎么办?您可以使用联接执行此操作,但不能使用相交/例外。因此,我可以看到在某些情况下,从长远来看,变化实际上最终变得更加复杂。
亚伦·伯特兰

2

我认为这是一个很好的解决方案。它在两个选择之间使用不存在子查询的联合。比结合Union和Except更好,因为您可以包括投影中不匹配的字段。

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.