2012-02-02 80 views
21

我只是讀有關EXCEPT和INTERSECT MSDN Library中和整個相交如何使用這個例子就是:爲什麼EXCEPT在T-SQL中存在?

USE AdventureWorks2008R2 GO 
SELECT ProductID 
FROM Production.Product 
INTERSECT 
SELECT ProductID 
FROM Production.WorkOrder ; 
--Result: 238 Rows (products that have work orders) 

也許我老土,但我通常會用下面的代碼來實現同樣的結果:

SELECT P.ProductID 
FROM Production.Product P 
INNER JOIN Production.WorkOrder W ON W.ProductID = P.ProductID 

我失去的東西,或者是相交一樣INNER JOIN?使用其中一種可以帶來性能上的好處嗎?

除了相同的問題。這是怎麼回事:

從這個
USE AdventureWorks2008R2; 
GO 
SELECT ProductID 
FROM Production.Product 
EXCEPT 
SELECT ProductID 
FROM Production.WorkOrder ; 
--Result: 266 Rows (products without work orders) 

不同:

SELECT P.ProductID 
FROM Production.Product P 
LEFT JOIN Production.WorkOrder W ON W.ProductID = P.ProductID 
WHERE W.ProductID IS NULL 

+2

-1:這不是INTERSECT的工作方式。您的第一個示例不返回具有工單的產品;它將返回與產品的工單的ID號相同的任何產品的ID。 – 2012-02-02 04:06:01

回答

22

我只關注EXCEPT,因爲我對它更熟悉。另外,作爲一個免責聲明,我的例子將在Sqlite中,因爲我在Linux上。但是,Sqlite和SQL Server都應該支持這個功能。

兩個INTERSECTEXCEPT設置運營商,relational algebra從基本思想而產生。他們操作截然不同的值,被設置爲運營商。

你的例子很簡單。我會舉一個反例,使用Sqlite版本的Northwind示例數據庫。

假設您想獲得以EmployeeID爲5的訂單的所有客戶的客戶ID,但不是那些也以6的EmployeeID作出訂單的客戶的客戶ID。這簡單且自然,具有EXCEPT

SELECT CustomerID FROM orders 
WHERE EmployeeID = 5 
EXCEPT 
SELECT CustomerID FROM orders 
WHERE EmployeeID = 6 

這會在我的Northwind版本上返回14行。

假設您決定使用JOIN s來重寫。也許這樣?

SELECT o1.CustomerID 
FROM orders o1 INNER JOIN orders o2 ON o1.CustomerID = o2.CustomerID 
WHERE o1.EmployeeID = 5 AND o2.EmployeeID != 6 

哎呀,525行。也許增加一個DISTINCT

SELECT DISTINCT o1.CustomerID 
FROM orders o1 INNER JOIN orders o2 ON o1.CustomerID = o2.CustomerID 
WHERE o1.EmployeeID = 5 AND o2.EmployeeID != 6 

現在它是28行,仍然比我們得到的EXCEPT更多。原因是這不會刪除已經用6進行了訂單的客戶ID。相反,它返回全部訂單號爲5的訂單ID和一些 6以外的EmployeeID,無論它們是否也有訂單EmployeeID 6.

簡而言之,EXCEPTINTERSECT是集合運算符,用於比較兩個查詢,返回唯一的元組,並且當然可以使用它們。

+3

可以編寫代碼等從 此選擇o1.CustomerId( 選擇客戶ID從訂單其中僱員= 5 )作爲O1 左外連接 ( 從訂單選擇的CustomerID其中僱員= 6 )作爲O1,O2 。 CustomerID = o2.CustomerID 其中o2.CustomerID爲空 – danmiao 2014-10-15 00:51:50

0

在我看來EXCEPTINTERSECT被用來做同樣的事情JOIN命令,但它與簡單的表沒有主鍵,例如:

INTERSECT

SELECT FIRSTNAME, 
     LASTNAME, 
     ADDRESSLINE1, 
     CITY, 
     STATEPROVINCECODE, 
     POSTALCODE 
FROM MANAGER 
EXCEPT 
SELECT FIRSTNAME, 
     LASTNAME, 
     ADDRESSLINE1, 
     CITY, 
     STATEPROVINCECODE, 
     POSTALCODE 
FROM CUSTOMER 

而且具有與JOIN相同的結果,你必須做到:

SELECT M.FIRSTNAME, 
     M.LASTNAME, 
     M.ADDRESSLINE1, 
     M.CITY, 
     M.STATEPROVINCECODE, 
     M.POSTALCODE 
FROM  MANAGER M 
WHERE NOT EXISTS (SELECT * 
        FROM CUSTOMER C 
        WHERE M.FIRSTNAME = C.FIRSTNAME 
          AND M.LASTNAME = C.LASTNAME 
          AND M.ADDRESSLINE1 = C.ADDRESSLINE1 
          AND M.CITY = C.CITY 
          AND M.POSTALCODE = C.POSTALCODE) 
GROUP BY M.FIRSTNAME,M.LASTNAME,M.ADDRESSLINE1,M.CITY, 
     M.STATEPROVINCECODE,M.POSTALCODE 

更多信息here

1

你的你的「等價物」查詢的例子是錯誤的 - 與INTERSECT查詢並不總是返回相同的結果INNER JOIN與同爲EXCEPTLEFT JOIN

看大約INTERSECT具體例如:

DECLARE @t TABLE(t INT NOT NULL) 
DECLARE @x TABLE(x INT NOT NULL) 

INSERT @t 
VALUES (1), (2), (3) 

INSERT @x VALUES(1), (1), (1) 

SELECT t FROM @t 
INTERSECT SELECT x FROM @x 

SELECT t FROM @t 
INNER JOIN @x ON x = t 

INTERSECT更像(但不相同)作爲IN子句:

SELECT t FROM @t 
WHERE t IN (select x FROM @x) 

或作爲EXISTS

SELECT t FROM @t 
WHERE EXISTS (select * FROM @x WHERE x = t) 

您可以適應EXCEPT條款的相同示例。

+0

你是對的,但看到我的理論背後的理論...... – gbn 2012-02-02 08:55:42

19
  • INTERSECT和EXCEPT是半連接
  • 聯接是相等聯接

所以,當你加入相匹配的,比如說2桌,5列3行

  • JOIN給出15行
  • INTERSECT給出3行

EXCEPT類似於OUTER JOIN出於同樣的原因

雖然我們對大約半聯接,然後大多

  • INTERSECT給出相同的結果爲EXISTS
  • EXCEPT給出了相同的結果,NOT EXISTS

的 「主要」 一詞,因爲這兩個INTERSECT和EXCEPT

編輯,這一切

DECLARE @t1 TABLE (t1col INT); 
INSERT @t1 VALUES (1), (2), (2), (3), (3), (5), (5); 

DECLARE @t2 TABLE (t2col INT); 
INSERT @t2 VALUES (1), (2), (3), (4); 

SELECT 'INNER JOIN', * FROM @t1 t1 JOIN @t2 t2 ON t1.t1col = t2.t2col -- same both ways 

SELECT 't1 INTERSECT t2', * FROM @t1 INTERSECT SELECT 't1 INTERSECT t2', * FROM @t2; 

SELECT 't2 INTERSECT t1', * FROM @t2 INTERSECT SELECT 't2 INTERSECT t1', * FROM @t1; 

SELECT 't1 EXISTS t2', * FROM @t1 t1 
WHERE EXISTS (SELECT * FROM @t2 t2 WHERE t1.t1col = t2.t2col); 

SELECT 't2 EXISTS t1', * FROM @t2 t2 
WHERE EXISTS (SELECT * FROM @t1 t1 WHERE t1.t1col = t2.t2col); 

SELECT 't1 LEFT JOIN t2, IS NULL', * FROM @t1 t1 LEFT JOIN @t2 t2 ON t1.t1col = t2.t2col WHERE t2.t2col IS NULL 
SELECT 't2 LEFT JOIN t1, IS NULL', * FROM @t2 t2 LEFT JOIN @t1 t1 ON t1.t1col = t2.t2col WHERE t1.t1col IS NULL 

SELECT 't1 EXCEPT t2', * FROM @t1 EXCEPT SELECT 't1 EXCEPT t2', * FROM @t2; 

SELECT 't2 EXCEPT t1', * FROM @t2 EXCEPT SELECT 't2 EXCEPT t1', * FROM @t1; 

SELECT 't1 NOT EXISTS t2', * FROM @t1 t1 
WHERE NOT EXISTS (SELECT * FROM @t2 t2 WHERE t1.t1col = t2.t2col); 

SELECT 't2 NOT EXISTS t1', * FROM @t2 t2 
WHERE NOT EXISTS (SELECT * FROM @t1 t1 WHERE t1.t1col = t2.t2col); 

更新的快速演示:2013年2月。增加額外的專欄來描述操作

+0

+1綜合! – 2012-02-02 09:18:01

+1

@Mikael Eriksson:我錯了,修正了。在 – gbn 2012-02-02 09:54:41

+0

之前我沒有足夠好的演示腳本其實,回頭看,不是'EXCEPT' [抗聯接](http://en.wikipedia.org/wiki/Relational_algebra#Joins_and_join-like_operators),而不是半連接? – voithos 2014-02-05 07:16:39