2つのテーブルが結合されています。
Aには多くのBがあります
通常は次のようにします:
select * from a,b where b.a_id = a.id
Bにレコードがあるaからすべてのレコードを取得する。
Bに何もないaのレコードだけを取得するにはどうすればよいですか?
select * from a where id not in (select a_id from b)
または、このスレッドの他の人が言うように:
select a.* from a
left outer join b on a.id = b.a_id
where b.a_id is null
select * from a
left outer join b on a.id = b.a_id
where b.a_id is null
別のアプローチ:
select * from a where not exists (select * from b where b.a_id = a.id)
「exists」アプローチは、内部クエリにアタッチする必要がある他の「where」句がある場合に役立ちます。
SELECT id FROM a
EXCEPT
SELECT a_id FROM b;
SELECT <columnns>
FROM a WHERE id NOT IN (SELECT a_id FROM b)
外部結合を使用すると、おそらく( 'not in'を使用するよりも)はるかに優れたパフォーマンスが得られます。
select * from a left outer join b on a.id = b.a_id where b.a_id is null;
1つの結合の場合はかなり高速ですが、約5,000万のレコードと外部キーによる4つ以上の結合があるデータベースからレコードを削除する場合、数分かかります。次のようなWHERE NOT IN条件を使用する方がはるかに高速です。
select a.* from a
where a.id NOT IN(SELECT DISTINCT a_id FROM b where a_id IS NOT NULL)
//And for more joins
AND a.id NOT IN(SELECT DISTINCT a_id FROM c where a_id IS NOT NULL)
カスケード削除を構成していない場合に備えて、この削除方法もお勧めします。このクエリは数秒しかかかりません。
それを書く別の方法
select a.*
from a
left outer join b
on a.id = b.id
where b.id is null
痛い、ネイサンに殴られた:)
これにより、IN句のnullから保護され、予期しない動作を引き起こす可能性があります。
select * from a where id not in(select [a id] from b where [a id] is not null)
最初のアプローチは
select a.* from a where a.id not in (select b.ida from b)
2番目のアプローチは
select a.*
from a left outer join b on a.id = b.ida
where b.ida is null
最初のアプローチは非常に高価です。 2番目のアプローチの方が優れています。
PostgreSql 9.4では、「クエリの説明」関数と最初のクエリをcost = 0.00..1982043603.32のコストとして実行しました。代わりに、コストとしての結合クエリcost = 45946.77..45946.78
たとえば、どの車両にも対応していないすべての製品を検索します。 10万の製品と100万を超える互換性があります。
select count(*) from product a left outer join compatible c on a.id=c.idprod where c.idprod is null
結合クエリは約5秒かかりましたが、サブクエリバージョンは3分後に終了していません。