同じような列名を持つ2つのテーブルがあり、右側のテーブルにないレコードを左側のテーブルから返す必要がありますか?私は両方のテーブルを比較するのに役立つ主キー(列)を持っています。どの結合が優先されますか?
T-SQLを要求している場合は、まず基礎を見てみましょう。ここには、次の3種類の結合があり、それぞれに次のような独自の論理処理フェーズがあります。
cross join
は最も簡単です。 Cartesian Product
という1つの論理クエリ処理フェーズのみを実装します。このフェーズは、結合への入力として提供される2つのテーブルで動作し、2つのデカルト積を生成します。つまり、1つの入力の各行が、他の入力のすべての行と一致します。したがって、一方のテーブルにm行、もう一方のテーブルにn行ある場合、結果にはm×n行が含まれます。Inner joins
を使用します。2つの論理クエリ処理フェーズを適用します。クロスジョインのように2つの入力テーブル間にA Cartesian product
を適用し、その後filters
句(Join condition
とも呼ばれる)で指定した述語に基づいてON
行を適用します。次に、3番目のタイプの結合であるOuter Joins
があります。
outer join
では、テーブル名の間にキーワードLEFT OUTER JOIN
、RIGHT OUTER JOIN
、またはFULL OUTER JOIN
を使用して、テーブルをpreserved
テーブルとしてマークします。 OUTER
キーワードはoptional
です。 LEFT
キーワードは、left table
の行が保持されることを意味します。 RIGHT
キーワードは、right table
の行が保持されることを意味します。 FULL
キーワードは、both
、left
、およびright
テーブルの行が保持されることを意味します。
outer join
の3番目の論理クエリ処理フェーズでは、保存されたテーブルから、ON
述語に基づいて他のテーブルに一致するものが見つからなかった行を識別します。このフェーズでは、これらの行を結合の最初の2つのフェーズで作成された結果テーブルに追加し、それらの外側の行の結合の非保存側からの属性のプレースホルダーとしてNULL
マークを使用します。
ここで質問を見てみましょう:右側のテーブルにない左側のテーブルからレコードを返すには、Left outer join
を使用し、結合の右側から属性のNULL
値を持つ行をフィルターで除外します。
これを試して
SELECT f.*
FROM first_table f LEFT JOIN second_table s ON f.key=s.key
WHERE s.key is NULL
詳細については、この記事をお読みください: SQL Serverへの参加
NOT EXISTSも使用したいです。インデックスが適切であれば、パフォーマンスに関しては、LEFT JOINと同等以上のパフォーマンスを発揮するはずです。さらに、読みやすくなっています。
SELECT Column1
FROM TableA a
WHERE NOT EXISTS ( SELECT Column1
FROM Tableb b
WHERE a.Column1 = b.Column1
)
私は他の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
このページでは、さまざまな結合タイプの適切な内訳と、ベン図の視覚化が役立ちます。
コメントによると、これはその音からの非常に基本的なクエリなので、結合と実際の意味の違いを理解するようにしてください。
チェックアウト 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
キーフィールドが含まれていない左のテーブルから*を選択します(右のテーブルからキーフィールドを選択します)
これは実際の仕事の例です。過去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つの簡単な方法があります:
左結合の使用:
select distinct a.UserID
from @6To3MonthsUsers a
left join @Last3MonthsUsers b
on a.UserID = b.UserID
where b.UserID is null
ありませんで:
select distinct a.UserID
from @6To3MonthsUsers a
where a.UserID not in (select b.UserID from @Last3MonthsUsers b)
どちらの方法でも同じ結果が得られますが、個人的には読みやすいので2番目の方法を好みます。