EXCEPT
演算子はSQL Server 2005で導入されましたが、NOT IN
とEXCEPT
の違いは何ですか?
同じことをしますか?例を挙げて簡単な説明をお願いします。
EXCEPT
とNOT IN
の間には2つの重要な違いがあります。
EXCEPT
は、右側のテーブルに表示されない左側のテーブルのDISTINCT
値をフィルタリングします。基本的には、DISTINCT
句を使用してNOT EXISTS
を実行するのと同じです。
また、2つのテーブル(またはテーブルの列のサブセット)がクエリの左側と右側に同じ数の列を持っていると想定しています。
たとえば、次のことはできません。
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でサブクエリが導入されていない場合、選択リストで指定できる式は1つだけです。
ただし、右側のテーブルのNOT IN
でフィルタリングされた値にNULL
が含まれている場合、空の結果セットが返され、予期しない結果になる可能性があります。
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)
上記の2つのクエリから、EXCEPT
は#NewCustomers
から3行を返し、#ExistingCustomers
と一致する1および3と重複する8を除外します。
NOT IN
は、この個別のフィルタリングを行わず、#NewCustomers
から4行を返し、重複した8を返します。
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
を確認する必要があります。この2つは Gail Shawのブログ で比較できます。
マーク・シンキンソンの優れたコメントへの追加:
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ではまだ実装されていません。