web-dev-qa-db-ja.com

SQL-右側のテーブルに見つからない左側のテーブルから行を返す方法

同じような列名を持つ2つのテーブルがあり、右側のテーブルにないレコードを左側のテーブルから返す必要がありますか?私は両方のテーブルを比較するのに役立つ主キー(列)を持っています。どの結合が優先されますか?

37
CloudJedi

T-SQLを要求している場合は、まず基礎を見てみましょう。ここには、次の3種類の結合があり、それぞれに次のような独自の論理処理フェーズがあります。

  1. cross joinは最も簡単です。 Cartesian Productという1つの論理クエリ処理フェーズのみを実装します。このフェーズは、結合への入力として提供される2つのテーブルで動作し、2つのデカルト積を生成します。つまり、1つの入力の各行が、他の入力のすべての行と一致します。したがって、一方のテーブルにm行、もう一方のテーブルにn行ある場合、結果にはm×n行が含まれます。
  2. 次にInner joinsを使用します。2つの論理クエリ処理フェーズを適用します。クロスジョインのように2つの入力テーブル間にA Cartesian productを適用し、その後filters句(Join conditionとも呼ばれる)で指定した述語に基づいてON行を適用します。
  3. 次に、3番目のタイプの結合であるOuter Joinsがあります。

    outer joinでは、テーブル名の間にキーワードLEFT OUTER JOINRIGHT OUTER JOIN、またはFULL OUTER JOINを使用して、テーブルをpreservedテーブルとしてマークします。 OUTERキーワードはoptionalです。 LEFTキーワードは、left tableの行が保持されることを意味します。 RIGHTキーワードは、right tableの行が保持されることを意味します。 FULLキーワードは、bothleft、およびrightテーブルの行が保持されることを意味します。

    outer joinの3番目の論理クエリ処理フェーズでは、保存されたテーブルから、ON述語に基づいて他のテーブルに一致するものが見つからなかった行を識別します。このフェーズでは、これらの行を結合の最初の2つのフェーズで作成された結果テーブルに追加し、それらの外側の行の結合の非保存側からの属性のプレースホルダーとしてNULLマークを使用します。

ここで質問を見てみましょう:右側のテーブルにない左側のテーブルからレコードを返すには、Left outer joinを使用し、結合の右側から属性のNULL値を持つ行をフィルターで除外します。

33
Deepshikha

これを試して

SELECT f.*
FROM first_table f LEFT JOIN second_table s ON f.key=s.key
WHERE s.key is NULL

詳細については、この記事をお読みください: SQL Serverへの参加

enter image description here

49
Shamseer K

NOT EXISTSも使用したいです。インデックスが適切であれば、パフォーマンスに関しては、LEFT JOINと同等以上のパフォーマンスを発揮するはずです。さらに、読みやすくなっています。

SELECT Column1
FROM TableA a
WHERE NOT EXISTS ( SELECT Column1
                   FROM Tableb b
                   WHERE a.Column1 = b.Column1
                 )
5
viejoEngineer

私は他の2つの答えにコード例を追加することしかできません:しかし、私はそれを実際に見るのが役立つことがわかります(私の意見では、他の答えはそれを説明しているのでより良いです)。

DECLARE @testLeft TABLE (ID INT, SomeValue VARCHAR(1))
DECLARE @testRight TABLE (ID INT, SomeOtherValue VARCHAR(1))

INSERT INTO @testLeft (ID, SomeValue) VALUES (1, 'A')
INSERT INTO @testLeft (ID, SomeValue) VALUES (2, 'B')
INSERT INTO @testLeft (ID, SomeValue) VALUES (3, 'C')


INSERT INTO @testRight (ID, SomeOtherValue) VALUES (1, 'X')
INSERT INTO @testRight (ID, SomeOtherValue) VALUES (3, 'Z')

SELECT l.*
FROM 
    @testLeft l
     LEFT JOIN 
    @testRight r ON 
        l.ID = r.ID
WHERE r.ID IS NULL 
2
AHiggins

このページでは、さまざまな結合タイプの適切な内訳と、ベン図の視覚化が役立ちます。

コメントによると、これはその音からの非常に基本的なクエリなので、結合と実際の意味の違いを理解するようにしてください。

チェックアウト http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

次のようなクエリを探しています:

DECLARE @table1 TABLE (test int)
DECLARE @table2 TABLE (test int)

INSERT INTO @table1
(
    test
)
SELECT 1
UNION ALL SELECT 2

INSERT INTO @table2
(
    test
)
SELECT 1
UNION ALL SELECT 3

-- Here's the important part
SELECT  a.*
FROM    @table1 a
LEFT    join @table2 b on a.test = b.test -- this will return all rows from a
WHERE   b.test IS null -- this then excludes that which exist in both a and b

-- Returned results:

2
1
Kritner

キーフィールドが含まれていない左のテーブルから*を選択します(右のテーブルからキーフィールドを選択します)

0
George Let

これは実際の仕事の例です。過去6か月間にサイトから購入したが過去3か月には購入していないユーザーのリストを提供するよう求められました。

私にとって、最も理解しやすい方法は次のとおりです。

--Users that bought from us 6 months ago and between 3 months ago.
DECLARE @6To3MonthsUsers table (UserID int,OrderDate datetime)
INSERT @6To3MonthsUsers
    select u.ID,opd.OrderDate
        from OrdersPaid opd
        inner join Orders o
        on opd.OrderID = o.ID
        inner join Users u
        on o.BuyerID = u.ID
        where 1=1 
        and opd.OrderDate BETWEEN DATEADD(m,-6,GETDATE()) and DATEADD(m,-3,GETDATE())

--Users that bought from us in the last 3 months
DECLARE @Last3MonthsUsers table (UserID int,OrderDate datetime)
INSERT @Last3MonthsUsers
    select u.ID,opd.OrderDate
        from OrdersPaid opd
        inner join Orders o
        on opd.OrderID = o.ID
        inner join Users u
        on o.BuyerID = u.ID
        where 1=1 
        and opd.OrderDate BETWEEN DATEADD(m,-3,GETDATE()) and GETDATE()

ここで、これらの2つのテーブルを手に入れて、テーブルからユーザー@ 6To3MonthsUsersのみを取得する必要があります@ Last3MonthsUsersテーブル。

それを達成する2つの簡単な方法があります:

  1. 左結合の使用:

    select distinct a.UserID
    from @6To3MonthsUsers a
    left join @Last3MonthsUsers b
    on a.UserID = b.UserID
    where b.UserID is null
    
  2. ありませんで:

    select distinct a.UserID
    from @6To3MonthsUsers a
    where a.UserID not in (select b.UserID from @Last3MonthsUsers b)
    

どちらの方法でも同じ結果が得られますが、個人的には読みやすいので2番目の方法を好みます。

0
Offir Pe'er