Симметричная разностная операция в Transact-SQL?

10

Я всегда знал об UNIONоператоре в SQL, но только недавно обнаружил, что были и другие операторы множеств, INTERSECTи EXCEPT. Я не смог найти оператора, который выполняет четвертый оператор большого набора, симметричную разность (например, противоположность 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?

KutuluMike
источник
2
(a EXCEPT b) UNION ALL (b EXCEPT a);может быть более эффективным.
ypercubeᵀᴹ 15.07.14
@ypercube, который выполняет 3 соединения или операции, подобные соединению. Я не могу придумать причину, по которой это может быть более эффективным, чем полное объединение.
USR
@usr это на самом деле 2 операции, подобные соединению, а не 3. Union All - это гораздо менее затратная операция. Я согласен, что FULL JOINможет быть более эффективным. Тестирование может выявить, что лучше. И, конечно же, если требуется больше / разных столбцов в каждой таблице, моё решение нелегко расширить.
ypercubeᵀᴹ

Ответы:

3

Все операторы множеств переводятся в соединения или операторы, подобные соединениям. Вы можете убедиться в этом в плане запроса.

По этой причине полное внешнее соединение, которое у вас есть, является наиболее эффективным, что вы можете сделать. Конечно, несмотря на редкую ситуацию, в которой оптимизатор выбирает неверный план, а перезапись оказывается более удачной благодаря удаче. Это всегда может случиться.

USR
источник
Это имеет смысл, однако, причина, по которой мне нравится использовать операторы set, заключается в том, что они не создают «лишних столбцов» ... Я могу делать что-то вроде SELECT Id FROM A WHERE <stuff> EXCEPT Select Id FROM A WHERE <other stuff>и получить один список Id. Я не могу понять, как сделать это с полным объединением ... мне просто нужно иметь дело с двумя наборами Idстолбцов и объединять их вместе самостоятельно?
KutuluMike
Вы можете сказать ISNULL(a.Col, b.Col) AS Col. Оберните это в производную таблицу или CTE, и вы сможете использовать «свернутый» набор результатов для дальнейшей работы с ним. (Кстати, я согласен, что симметричный разностный оператор должен существовать.)
usr
2
@MichaelEdenfield С другой стороны, что делать, когда вы хотите, чтобы другие столбцы не использовались в сравнении / различении? Вы можете сделать это с помощью соединения, но не с помощью intersect / исключением. Так что в некоторых случаях я мог видеть, что вариации на самом деле становятся намного более сложными в долгосрочной перспективе.
Аарон Бертран
2

Я думаю, что это довольно хорошее решение. Он использует объединение всех двух выборок с подзапросами Not Exists. Лучше, чем объединение 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)
Даррел Ли
источник