データベースに主キーがバインドされた2つのテーブルがあり、それらの間に互いに素なセットを見つけたいと思っています。例えば、
Table1
には列(ID, Name
)とサンプルデータがあります:(1 ,John), (2, Peter), (3, Mary)
Table2
には列(ID, Address
)とサンプルデータがあります:(1, address2), (2, address2)
したがって、SQLクエリを作成して、table1
にないtable2
からIDを持つ行をフェッチするにはどうすればよいですか。この場合、(3, Mary)
が返されますか?
Ps。 IDは、これら2つのテーブルの主キーです。
前もって感謝します。
これを試して
SELECT ID, Name
FROM Table1
WHERE ID NOT IN (SELECT ID FROM Table2)
LEFT JOIN
を使用
SELECT a.*
FROM table1 a
LEFT JOIN table2 b
on a.ID = b.ID
WHERE b.id IS NULL
それぞれ〜2M行の2つのテーブルを使用して(postgres 9.5で)いくつかのテストを実行しました。以下のこのクエリは、提案されている他のクエリよりも少なくとも5 *優れたパフォーマンスを発揮しました。
-- Count
SELECT count(*) FROM (
(SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;
-- Get full row
SELECT table1.* FROM (
(SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;
上記の@John Wooのコメント/リンクで指摘されたポイントを念頭に置いて、これは私が通常それを処理する方法です:
SELECT t1.ID, t1.Name
FROM Table1 t1
WHERE NOT EXISTS (
SELECT TOP 1 NULL
FROM Table2 t2
WHERE t1.ID = t2.ID
)
それには基本的に3つのアプローチがあります:not exists
、not in
、left join / is null
。
SELECT l.*
FROM t_left l
LEFT JOIN
t_right r
ON r.value = l.value
WHERE r.value IS NULL
SELECT l.*
FROM t_left l
WHERE l.value NOT IN
(
SELECT value
FROM t_right r
)
SELECT l.*
FROM t_left l
WHERE NOT EXISTS
(
SELECT NULL
FROM t_right r
WHERE r.value = l.value
)
どっちがいいですか?この質問に対する答えは、主要な特定のRDBMSベンダーに分類した方が良いかもしれません。一般的に、サブクエリのレコード数の大きさが不明な場合は、select ... where ... in (select...)
の使用を避ける必要があります。一部のベンダーはサイズを制限する場合があります。たとえば、Oracleには 1,000の制限 があります。最善の方法は、3つすべてを試して、実行計画を示すことです。
具体的にはPostgreSQLから、NOT EXISTS
とLEFT JOIN / IS NULL
の実行計画は同じです。個人的には、NOT EXISTS
オプションを好むのは、意図がよりよくわかるからです。すべてのセマンティクスは、Aでそのpk 存在しない Bのレコードを検索することです。
古いが、まだPostgreSQLに特有であるが、 https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b) --For count
SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b) --For results