为什么在T-SQL中存在EXCEPT?

fie*_*ish 24 t-sql

我刚刚在MSDN Library中阅读有关EXCEPT和INTERSECT的内容,并且遇到了如何使用INTERSECT的示例:

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

也许我是老式的,但我通常会使用以下代码来实现相同的结果:

SELECT P.ProductID 
FROM Production.Product P 
INNER JOIN Production.WorkOrder W ON W.ProductID = P.ProductID
Run Code Online (Sandbox Code Playgroud)

我错过了什么,或者是和INNER JOIN一样的INTERSECT?使用一个优于另一个是否有性能优势?

同样的问题除外.这怎么样:

USE AdventureWorks2008R2;
GO
SELECT ProductID 
FROM Production.Product
EXCEPT
SELECT ProductID 
FROM Production.WorkOrder ;
--Result: 266 Rows (products without work orders)
Run Code Online (Sandbox Code Playgroud)

不同于此:

SELECT P.ProductID 
FROM Production.Product P 
LEFT JOIN Production.WorkOrder W ON W.ProductID = P.ProductID
WHERE W.ProductID IS NULL
Run Code Online (Sandbox Code Playgroud)

voi*_*hos 25

我会专注于EXCEPT因为我对它更熟悉.此外,作为免责声明,我的例子将在Sqlite中,因为我在Linux机器上.但是,Sqlite和SQL Server都应该支持该功能.

这两个INTERSECTEXCEPT设置运营商,从基本思想而产生的关系代数.它们以不同的值运行,是设置运算符.

你的例子很简单.我将给出一个反例,使用Northwind示例数据库的Sqlite版本.

比方说,你想与谁5雇员作出的命令,所有客户的CustomerIDs,而不是那些谁也与雇员由6命令这是简单而自然有EXCEPT.

SELECT CustomerID FROM orders
WHERE EmployeeID = 5
EXCEPT
SELECT CustomerID FROM orders
WHERE EmployeeID = 6
Run Code Online (Sandbox Code Playgroud)

这会在我的Northwind版本上返回14行.

假设您决定使用JOINs 重写它.也许是这样的?

SELECT o1.CustomerID
FROM orders o1 INNER JOIN orders o2 ON o1.CustomerID = o2.CustomerID
WHERE o1.EmployeeID = 5 AND o2.EmployeeID != 6
Run Code Online (Sandbox Code Playgroud)

哎呀,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
Run Code Online (Sandbox Code Playgroud)

现在它有28行,仍然远远超过我们所获得的数量EXCEPT.其原因是,这是不删除已作出命令6. CustomerIDs相反,它返回所有具有订货5和CustomerIDs 一些超过6 EmployeeID为其它,无论他们是否还与雇员6的顺序.

简而言之,EXCEPT并且INTERSECT设置运算符来比较两个查询,返回唯一元组,并且肯定有它们的用途.

  • 您可以编写这样的代码选择o1.CustomerId(从EmployeeID = 5的订单中选择CustomerId)作为o1左外连接(从EmployeeID = 6的订单中选择CustomerID)作为o1 on o1.CustomerID = o2.CustomerID其中o2.CustomerID一片空白 (5认同)

gbn*_*gbn 22

  • INTERSECT和EXCEPT是半连接
  • JOIN是equi-join

因此,当您连接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);
Run Code Online (Sandbox Code Playgroud)

更新:2013年2月.添加了额外的列来描述操作