Transact-SQL'de simetrik fark işlemi?


10

Ben her zaman UNIONSQL operatör hakkında biliyordum , ama sadece son zamanlarda başka set operatörleri olduğunu keşfetti INTERSECTve EXCEPT. Dördüncü büyük set operatörünü, simetrik farkı (örneğin tersini INTERSECT) yapan bir operatör bulamadım .

Gibi bir şey kullanarak istenen çıktıyı alabilirim gibi görünüyor

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

(önceliği doğru bulduğumu varsayarak) veya tam bir anti-birleştirme yaparak:

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

Ancak her ikisi de, özellikle diğer üç temel küme işlemine kıyasla oldukça yoğun sorgular gibi görünüyor. SQL'de simetrik bir fark işlemi var mı ve bunu belgelerde bulamıyorum? Yoksa T-SQL'de uygulamak için "kanonik" bir yolu var mı?


2
(a EXCEPT b) UNION ALL (b EXCEPT a);daha verimli olabilir.
ypercubeᵀᴹ

@ ypercube 3 birleştirme veya birleştirme benzeri işlemler yapar. Bunun tam bir birleşmeden daha etkili olabileceğinin hiçbir nedenini düşünemiyorum.
usr

@usr aslında 3 değil, 2 birleştirme benzeri işlem. Union All çok daha az maliyetli bir işlemdir. Bunun FULL JOINdaha verimli olabileceğini kabul ediyorum . Test hangisinin daha iyi olduğunu ortaya çıkarabilir. Ve elbette, her tablodan daha fazla / farklı sütun gerekiyorsa, çözümüm kolayca genişletilemez.
ypercubeᵀᴹ

Yanıtlar:


3

Tüm set operatörleri birleştirme veya birleştirme benzeri operatörlere çevrilir. Sorgu planında buna tanık olabilirsiniz.

Bu nedenle, sahip olduğunuz tam dış birleşim yapabileceğiniz en verimli şeydir. Elbette, optimize edicinin kötü bir plan seçtiği ve yeniden yazmanın şansla daha iyi performans gösterdiği umarım nadir görülen durumu göz ardı etmek. Bu her zaman olabilir.


Bununla birlikte, set operatörlerini kullanmaktan hoşlanmamın nedeni, "ekstra sütunlar" oluşturmadıkları için ... Mantıklı şeyler yapabilir SELECT Id FROM A WHERE <stuff> EXCEPT Select Id FROM A WHERE <other stuff>ve tek bir liste alabilirim Id. Bunu tam bir birleşimle nasıl yapacağımı anlayamıyorum ... sadece iki Idsütun kümesiyle başa çıkıp bunları kendim bir araya getirmem gerekiyor mu?
KutuluMike

Diyebilirsiniz ISNULL(a.Col, b.Col) AS Col. Bunu türetilmiş bir tabloya veya CTE'ye sarın ve üzerinde daha fazla işlem yapmak için "katlanmış" sonuç kümesini kullanabilirsiniz. (Btw, simetrik fark operatörünün olması gerektiğine katılıyorum.)
usr

2
@MichaelEdenfield Öte yandan, karşılaştırma / farklı olarak kullanılmayan diğer sütunları ne zaman istersiniz ? Bunu bir birleştirme ile yapabilirsiniz, ancak kesişme / hariç olarak yapamazsınız. Bazı durumlarda varyasyonun uzun vadede çok daha karmaşık hale geldiğini görebiliyordum.
Aaron Bertrand

2

Bence bu oldukça iyi bir çözüm. Mevcut Olmayan alt sorguları ile iki seçim arasında bir birlik kullanır. Birleşim ve Dışlama'yı birleştirmekten daha iyi çünkü projeksiyonda eşleşmeyen alanları ekleyebilirsiniz.

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.