2012-02-02 18 views
21

私はちょうどMSDNライブラリでEXCEPTとINTERSECTについて読んとINTERSECTを使用する方法のこの例に出くわした:EXCEPTがT-SQLに存在するのはなぜですか?

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

は、たぶん私は昔ながらのだけど、私は一般的に達成するために、次のコードを使用します同じ結果:

SELECT P.ProductID 
FROM Production.Product P 
INNER JOIN Production.WorkOrder W ON W.ProductID = P.ProductID 

私は何かが見つからないか、INTERNECT INNER JOINと同じですか? 1つを他のものに使用することにパフォーマンス上の利点はありますか?

EXCEPTと同じ質問です。

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

この異なる:これはどのようにある

SELECT P.ProductID 
FROM Production.Product P 
LEFT JOIN Production.WorkOrder W ON W.ProductID = P.ProductID 
WHERE W.ProductID IS NULL 

?私の意見EXCEPTINTERSECT

+2

-1:それはINTERSECTの仕組みではありません。最初の例では、作業指示のある製品は返されません。製品の作業オーダーのIDと同じIDを持つ製品のIDを返します。 O1 は、外側左よう –

答えて

22

EXCEPTに焦点を合わせるつもりです。なぜなら、私はそれに精通しているからです。また、免責事項として、私の例はSqliteになります。なぜなら私はLinuxの箱の上にいるからです。ただし、SqliteとSQL Serverの両方でこの機能をサポートする必要があります。

INTERSECTEXCEPTの両方は、relational algebraの根底にある考え方に基づいて設定された演算子です。彼らはの異なる値で動作します。

あなたの例は単純です。私はNorthwindサンプルデータベースのSqlite版を使用して反例を説明します。

EmployeeIDが5の注文を行ったすべての顧客の得意先コードを取得したいが、EmployeeIDが6である注文者ではないとします。これはEXCEPTのシンプルで自然なものです。

SELECT CustomerID FROM orders 
WHERE EmployeeID = 5 
EXCEPT 
SELECT CustomerID FROM orders 
WHERE EmployeeID = 6 

これは、私のバージョンのNorthwindで14行を返します。

JOINを使用してこれを書き換えるとします。多分このような何か?

SELECT o1.CustomerID 
FROM orders o1 INNER JOIN orders o2 ON o1.CustomerID = o2.CustomerID 
WHERE o1.EmployeeID = 5 AND o2.EmployeeID != 6 

おっと、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 

は、今では私たちはEXCEPTとなっていたものよりもまだはるかに28行、です。理由は、これで注文が6で行われた得意先コードが削除されていないことになります。すべて注文が5およびの顧客IDがある 6以外の従業員ID EmployeeID 6.

簡潔に言えば、EXCEPTINTERSECTは、2つのクエリを比較して一意のタプルを返す演算子を設定しています。あなたの「同等」のクエリの

+3

あなたは( 社員= 5 注文から得意先選択) からこの選択o1.CustomerIdようなコードを書くことができO1にO2 として( 社員= 6 注文から得意先を選択) に参加します。 CustomerID = o2.CustomerID ここでo2.CustomerIDはnullです – danmiao

0

は、JOINコマンドと同じことを行うために使用されるが、例えば、主キーを持たないテーブルを持つことは簡単です:

INTERSECTで:

SELECT FIRSTNAME, 
     LASTNAME, 
     ADDRESSLINE1, 
     CITY, 
     STATEPROVINCECODE, 
     POSTALCODE 
FROM MANAGER 
EXCEPT 
SELECT FIRSTNAME, 
     LASTNAME, 
     ADDRESSLINE1, 
     CITY, 
     STATEPROVINCECODE, 
     POSTALCODE 
FROM CUSTOMER 

そして、JOINと同じ結果を持っている、あなたが行う必要があります。

SELECT M.FIRSTNAME, 
     M.LASTNAME, 
     M.ADDRESSLINE1, 
     M.CITY, 
     M.STATEPROVINCECODE, 
     M.POSTALCODE 
FROM  MANAGER M 
WHERE NOT EXISTS (SELECT * 
        FROM CUSTOMER C 
        WHERE M.FIRSTNAME = C.FIRSTNAME 
          AND M.LASTNAME = C.LASTNAME 
          AND M.ADDRESSLINE1 = C.ADDRESSLINE1 
          AND M.CITY = C.CITY 
          AND M.POSTALCODE = C.POSTALCODE) 
GROUP BY M.FIRSTNAME,M.LASTNAME,M.ADDRESSLINE1,M.CITY, 
     M.STATEPROVINCECODE,M.POSTALCODE 

詳しい情報here

1

あなたの例は間違っている - INTERSECTを持つクエリは、常にEXCEPTLEFT JOINためINNER JOINと同じと同じ結果を返しません。 INTERSECT約特定の例で

ルック:

DECLARE @t TABLE(t INT NOT NULL) 
DECLARE @x TABLE(x INT NOT NULL) 

INSERT @t 
VALUES (1), (2), (3) 

INSERT @x VALUES(1), (1), (1) 

SELECT t FROM @t 
INTERSECT SELECT x FROM @x 

SELECT t FROM @t 
INNER JOIN @x ON x = t 

INTERSECTがより似ている(なく同じINとして句:

SELECT t FROM @t 
WHERE t IN (select x FROM @x) 

又は

SELECT t FROM @t 
WHERE EXISTS (select * FROM @x WHERE x = t) 
EXISTSとして

同じ例をEXCEPT節に適合させることができます。

+0

あなたは正しいですが、その背後にある理論についての私の答えを見てください... – gbn

19
  • INTERSECTとEXCEPTは
  • は、等結合あなたが一致して2つのテーブル、たとえば、5行と3行

    • に参加するときに

    ですJOINの半加入されていますJOINは15行を返します

  • INTERSECTは3行を返します

EXCEPT与えEXCEPT INTERSECTは

  • をEXISTSと同じ結果が得られ、その後ほとんど

    • 、我々は半参加する程度にしている一方で、同様の理由

      ために、JOIN OUTERに似ていますNOTは、INTERSECTと

      01 EXCEPT両方のために、 "主に" 来る

    をEXISTSと同じ結果

    編集、すべてこの

    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); 
    

    アップデートのクイックデモを適用ご覧ください。操作を説明する追加の列を追加しました

  • +0

    +1包括的な! –

    +1

    @Mikael Eriksson:私は間違っています。私は十分なデモスクリプトを持っていませんでした – gbn

    +0

    実際に、振り返ってみると、[antijoin](http://en.wikipedia.org/wiki/Relational_algebra#Joins_and_join-like_operators)ではなく、セミジョイン? – voithos

    関連する問題