除了运算符vs NOT IN


Answers:


29

EXCEPT和之间有两个主要区别NOT IN

除了

EXCEPT过滤DISTINCT左侧表中未出现在右侧表中的值。本质上与NOT EXISTSwith DISTINCT子句相同。

它还希望两个表(或表中列的子集)在查询的左侧和右侧具有相同数量的列

例如,您不能执行以下操作:

SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB

这将导致错误:

使用UNION,INTERSECT或EXCEPT运算符组合的所有查询在其目标列表中必须具有相等数量的表达式。

不在

NOT IN不过滤DISTINCT值,并返回左侧表中未出现在右侧表中的所有值。

NOT IN 要求您将一个表中的单个列与另一表或子查询中的单个列进行比较。

例如,如果您的子查询返回多个列:

SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)

您会收到以下错误:

如果未使用EXISTS引入子查询,则只能在选择列表中指定一个表达式。

但是,如果右边的表中的包含NULL由过滤的值中的NOT IN,则返回一个空结果集,可能会产生意外结果。

CREATE TABLE #NewCustomers (ID INT);
CREATE TABLE #ExistingCustomers (ID INT);

INSERT INTO #NewCustomers
        ( ID )
VALUES
     (8), (9), (10), (1), (3), (8);

INSERT INTO #ExistingCustomers
        ( ID )
VALUES
        ( 1) , (2), (3), (4), (5);


-- EXCEPT filters for DISTINCT values
SELECT * FROM #NewCustomers AS nc
EXCEPT
SELECT * FROM #ExistingCustomers AS ec

-- NOT IN returns all values without filtering
SELECT * FROM #NewCustomers AS nc
WHERE ID NOT IN (SELECT ID FROM #ExistingCustomers AS ec)

从以上两个查询中,EXCEPT返回的3行#NewCustomers,过滤出匹配的1和3,#ExistingCustomers以及重复的8。

NOT IN不执行这种独特的过滤,并从#NewCustomers重复的8 返回4行。

如果我们现在在添加NULL#ExistingCustomers表格中,我们看到返回的结果相同EXCEPT,但NOT IN将返回一个空的结果集。

INSERT INTO #ExistingCustomers
        ( ID )
VALUES
        ( NULL );

-- With NULL values in the right-hand table, EXCEPT still returns the same results as above
SELECT * FROM #NewCustomers AS nc
EXCEPT
SELECT * FROM #ExistingCustomers AS ec

-- NOT IN now returns no results
SELECT * FROM #NewCustomers AS nc
WHERE ID NOT IN (SELECT ID FROM #ExistingCustomers AS ec)

DROP TABLE #NewCustomers;
DROP TABLE #ExistingCustomers;

相反NOT IN,您应该真正看一下,NOT EXISTS并且在Gail Shaw的博客上可以很好地比较两者。


如果合适,EXCEPT是否会使用索引?
JohnOpincar '17

1

Mark Sinkinson的出色评论的补充:

NOT IN要求您将一个表中的单个列与另一表或子查询中的单个列进行比较。

实际上,您可以执行NOT IN不止一列。
例如,这是完全合法的* SQL查询:

SELECT  E.first_name, E.last_name
FROM    employees E
WHERE   (E.first_name, E.last_name) NOT IN 
              (SELECT M.first_name, M.last_name FROM managers M)

这将返回,first_name并且last_name是所有员工,但同时也不是经理。

*:但是该构造尚未在SQL Server中实现。


-2

上面的NOT IN失败,因为在主查询和子查询中的谓词之间需要相关。如果省略它,则会得到一个UNCORRELATED子查询。

SELECT * FROM TableA AS nc不在其中的ID(SELECT ID,来自TableB AS ec的名称,其中nc.ID = ec.ID)

EXCEPT更好,它将不使用IS NULL / IS NOT NULL谓词来处理任何空行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.