Симетрична різниця операцій в 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?


2
(a EXCEPT b) UNION ALL (b EXCEPT a);може бути ефективнішим.
ypercubeᵀᴹ

@ypercube, який робить 3 приєднання або схожі операції. Я не можу придумати жодної причини, що це може бути ефективніше, ніж повне приєднання.
usr

@usr - це фактично 2 об'єднаних операції, а не 3. Union All набагато дешевша операція. Я погоджуюся, що це FULL JOINможе бути ефективнішим. Тестування дозволяє виявити, що найкраще. І звичайно, якщо потрібно більше / різних стовпців з кожної таблиці, моє рішення не легко розширюється.
ypercubeᵀᴹ

Відповіді:


3

Усі оператори набору переводяться на оператори приєднання або операції, що нагадують приєднання. Ви можете це засвідчити в плані запитів.

З цієї причини повне зовнішнє з'єднання, яке у вас є, є найефективнішим, що ви можете зробити. Зважаючи, звичайно, надіюсь на рідкісну ситуацію, в якій оптимізатор вибирає поганий план, а переписування виходить краще, ніж удача. Це завжди може статися.


Це має сенс, однак, мені подобається використовувати задані оператори, тому що вони не створюють "зайвих стовпців" ... Я можу робити такі речі, як 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, і ви можете використовувати набір результатів "складений" для подальшої роботи над нею. (Btw, я згоден, оператор симетричної різниці повинен існувати.)
usr

2
@MichaelEdenfield З іншого боку, що робити, коли ви хочете, щоб інші стовпці, які не використовуються в порівнянні / різниці? Ви можете зробити це з з'єднанням, але не з перетином / за винятком. Тож я міг бачити в деяких випадках, що варіація насправді в кінцевому рахунку стає набагато складнішою.
Аарон Бертран

2

Я думаю, що це досить вдале рішення. Він використовує об'єднання між двома виборами з підзапитами Not Exists. Краще, ніж поєднувати Union і виняток, тому що ви можете включити поля, які не відповідають проекції.

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.