回答:
とには2つの重要な違いがEXCEPT
ありNOT IN
ます。
EXCEPT
DISTINCT
右側のテーブルに表示されない左側のテーブルの値をフィルタリングします。これは、NOT EXISTS
with a DISTINCT
句を実行するのと本質的に同じです。
また、2つのテーブル(またはテーブルの列のサブセット)が、クエリの左側と右側に同じ数の列を持っていると想定しています
たとえば、次のことはできません。
SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB
これはエラーになります:
UNION、INTERSECT、またはEXCEPT演算子を使用して結合されたすべてのクエリは、ターゲットリストに同数の式を持っている必要があります。
NOT IN
DISTINCT
値をフィルタリングせず、右側のテーブルに表示されない左側のテーブルのすべての値を返します。
NOT IN
1つのテーブルの1つの列を別のテーブルまたはサブクエリの1つの列と比較する必要があります。
たとえば、サブクエリが複数の列を返す場合:
SELECT * FROM TableA AS nc
WHERE ID NOT IN (SELECT ID, Name FROM TableB AS ec)
次のエラーが表示されます。
サブクエリがEXISTSで導入されていない場合、選択リストに指定できる式は1つだけです。
ただし、右側のテーブルに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)
上記の2つのクエリEXCEPT
から#NewCustomers
、から3行を返し、一致する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
、実際に見てください。GailShawのブログでNOT EXISTS
この2つをよく比較できます。
マークシンキンソンの素晴らしいコメントへの追加:
NOT INでは、1つのテーブルの1つの列を別のテーブルまたはサブクエリの1つの列と比較する必要があります。
実際には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にはまだ構築が実装されていません。