web-dev-qa-db-ja.com

EXCEPT演算子とNOT IN

EXCEPT演算子はSQL Server 2005で導入されましたが、NOT INEXCEPTの違いは何ですか?

同じことをしますか?例を挙げて簡単な説明をお願いします。

19
Heisenberg

EXCEPTNOT INの間には2つの重要な違いがあります。

例外

EXCEPTは、右側のテーブルに表示されない左側のテーブルのDISTINCT値をフィルタリングします。基本的には、DISTINCT句を使用してNOT EXISTSを実行するのと同じです。

また、2つのテーブル(またはテーブルの列のサブセット)がクエリの左側と右側に同じ数の列を持っていると想定しています。

たとえば、次のことはできません。

SELECT ID, Name FROM TableA
EXCEPT
SELECT ID FROM TableB

これはエラーになります:

UNION、INTERSECT、またはEXCEPT演算子を使用して結合されたすべてのクエリは、ターゲットリストに同じ数の式を含める必要があります。

ありませんで

NOT INDISTINCT値をフィルターに掛けず、右側のテーブルに表示されない左側のテーブルのすべての値を返します。

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のブログ で比較できます。

30
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ではまだ実装されていません。

1
Michael Vigato