MySQLの「NOT IN」クエリ


181

簡単なクエリを実行してTable1、別のテーブルの列に主列の値が存在しないすべての行をスローしたいと思いました(Table2)。

私は使ってみました:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

代わりに、これは構文エラーをスローしています。グーグル検索は、MySQLがサポートしておらずNOT IN、非常に複雑なものを使用する必要があると人々が言っ​​ているフォーラムに私を導きました。これは本当ですか?または私は恐ろしい間違いをしていますか?


1
また、3つのテーブルから同様のデータが必要な場合はどうすればよいでしょうか。つまり、1つのtable1に2000のエントリがあり、他の2つのテーブル2&3にはそれぞれ500のエントリがあり、それらすべてに共通のフィールド「name」があります。「名前」に基づいてtable2&3に存在しないすべての詳細を表1から取得するにはどうすればよいですか。NOT INを2回使用できますか?

回答:


310

INを使用するには、セットが必要です。代わりに次の構文を使用してください。

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)

85
table2.principalできるときは注意してくださいNULL。その場合にはNOT IN、常に戻りますFALSEのでNOT INとして扱われる<> ALLようなサブクエリからすべての行を比較する、Table1.principal <> table2.principalと比較したときに失敗し、NULLTable1.principal <> NULLでなりませんTRUE。修正するには:NOT IN (SELECT principal FROM table2 WHERE principal IS NOT NULL)
バスティ2015

4
コメント@Bastiをありがとう!クエリが期待どおりに機能しなかった理由を理解するために多くの時間を費やしました。
gvas 2016年

3
「NOT IN」リスト内で「SELECT *」を使用しないことを忘れないでください。特定の列を選択する必要があります。そうしないと、このエラーが発生します。stackoverflow.com
questions

165

サブクエリオプションは既に回答されていますが、多くの場合、LEFT JOINこれを行うにはより高速な方法であることに注意してください。

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

複数のテーブルをチェックして、どのテーブルにも存在しないことを確認する場合(SRKRのコメントのように)、これを使用できます。

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL

2
私自身のテストでは、NOT IN&の両方で同じパフォーマンスがありましたLEFT JOIN。+1と
BufferStack 2012年

クエリが一度実行されると、内部DBキャッシュが原因で同じ結果が得られるはずです
Toote

私にとってはパフォーマンスははるかに優れていました。外部キーが設定されている間、私はさまざまなテーブルを実行しました。
Keenora Fluffball 2013

36

MySQLではNOT INとNOT EXISTSとLEFT JOIN / IS NULL

MySQLは、SQL Serverを除くすべてのシステムと同様に、一致する値が見つかるとすぐにLEFT JOIN/IS NULLを返すように最適化できます。FALSEこれは、この動作を文書化する唯一のシステムです。[…] MySQLはアルゴリズムの使用HASHMERGE結合に対応していないため、ANTI JOIN対応できるのはNESTED LOOPS ANTI JOIN

[…]

基本的に、[ NOT IN]LEFT JOIN/がIS NULL使用するプランとまったく同じですが、これらのプランはコードのさまざまなブランチによって実行され、の結果は異なって見えますEXPLAIN。アルゴリズムは実際には同じであり、クエリは同時に完了します。

[…]

[使用時のパフォーマンス低下NOT EXISTS]の正確な理由を特定することは困難です。この低下は線形であり、両方のフィールドにインデックスが付けられている限り、データ分布、両方のテーブルの値の数などに依存しないようです。MySQLには本質的に1つのジョブを実行する3つのコードがあるためEXISTS、原因となっているコードが何らかの追加のチェックを実行し、余分な時間がかかる可能性があります。

[…]

MySQLは、3つの方法すべてを最適化して、一種のを行うことができますNESTED LOOPS ANTI JOIN。[…]ただし、これらの3つのメソッドは、3つの異なるコードによって実行される3つの異なるプランを生成します。EXISTS述語を実行するコードは、約30%効率が低い[…]

MySQLで欠損値を検索する最善の方法は、LEFT JOIN/ IS NULLまたはNOT INではなくを使用することですNOT EXISTS

(強調を追加)


7

残念ながら、「NOT IN」句のMySqlの使用に問題があるようです。以下のスクリーンショットは、間違った結果を返すサブクエリオプションを示しています。

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.