Operacja różnicy symetrycznej w Transact-SQL?

10

Zawsze wiedziałem o UNIONoperatorze w SQL, ale dopiero niedawno odkryłem, że istnieją inne operatory zestawu INTERSECTi EXCEPT. Nie udało mi się znaleźć operatora, który wykonałby czwarty operator dużego zestawu, różnicę symetryczną (np. Odwrotnie INTERSECT.)

Wygląda na to, że mogę uzyskać pożądaną moc wyjściową za pomocą czegoś takiego

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

(zakładając, że mam pierwszeństwo), lub wykonując 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

Ale oba z nich wyglądają na dość intensywne zapytania, szczególnie w porównaniu do pozostałych trzech podstawowych operacji zestawu. Czy w SQL jest operacja różnicy symetrycznej i po prostu nie mogę jej znaleźć w dokumentacji? A może istnieje „kanoniczny” sposób na wdrożenie go w T-SQL?

KutuluMike
źródło
2
(a EXCEPT b) UNION ALL (b EXCEPT a);może być bardziej wydajny.
ypercubeᵀᴹ
@ypercube, który wykonuje 3 łączenia lub operacje podobne do łączenia. Nie mogę wymyślić żadnego powodu, dla którego mogłoby to być bardziej wydajne niż pełne połączenie.
usr
@usr to właściwie 2 operacje podobne do łączenia, a nie 3. Union All to znacznie mniej kosztowna operacja. Zgadzam się, że FULL JOINmoże być bardziej wydajny. Testy mogą ujawnić, który jest najlepszy. I oczywiście, jeśli potrzeba więcej / różnych kolumn z każdej tabeli, moje rozwiązanie nie jest łatwe do rozszerzenia.
ypercubeᵀᴹ

Odpowiedzi:

3

Wszystkie operatory zestawu są tłumaczone na sprzężenia lub operatory podobne do łączenia. Możesz to zobaczyć w planie zapytań.

Z tego powodu pełne połączenie zewnętrzne, które tam masz, jest najbardziej wydajne, co możesz zrobić. Pomijając oczywiście, miejmy nadzieję, rzadką sytuację, w której optymalizator wybiera zły plan, a przepisywanie tekstu działa lepiej dzięki szczęściu. To zawsze może się zdarzyć.

usr
źródło
Ma to jednak sens, dlatego lubię używać operatorów zestawu, ponieważ nie tworzą oni „dodatkowych kolumn” ... Mogę robić rzeczy takie jak SELECT Id FROM A WHERE <stuff> EXCEPT Select Id FROM A WHERE <other stuff>i uzyskać jedną listę Id. Nie mogę wymyślić, jak to zrobić z pełnym złączeniem ... czy muszę po prostu poradzić sobie z posiadaniem dwóch zestawów Idkolumn i zjednoczeniem ich z sobą?
KutuluMike
Można powiedzieć ISNULL(a.Col, b.Col) AS Col. Zawiń to w pochodną tabelę lub CTE i możesz użyć „złożonego” zestawu wyników do dalszej operacji na nim. (Przy okazji, zgadzam się, że operator różnicy symetrycznej powinien istnieć.)
usr
2
@MichaelEdenfield Z drugiej strony, a jeśli chcesz , aby inne kolumny nie były używane w porównaniu / odrębnym? Możesz to zrobić z łączeniem, ale nie z przecinaniem / wyjątkiem. Widziałem więc w niektórych przypadkach, że ta zmiana ostatecznie staje się znacznie bardziej złożona na dłuższą metę.
Aaron Bertrand
2

Myślę, że to całkiem dobre rozwiązanie. Używa połączenia wszystkich dwóch wyborów z podkwerendami Nieistniejące. Lepsze niż łączenie Union i Wyjątek, ponieważ możesz uwzględnić pola, które nie pasują do projekcji.

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
źródło