メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
EXISTS は「このサブクエリは何かを見つけたか」という、はいかいいえの質問をします。 サブクエリが何を返したかは気にせず、行があったかどうかだけを見ます。そのため、 関連する行の有無をテストしたいが、その列は 1 つも要らないときに適した道具です。 始める前に mysql -u root -p sakila でクライアントを開いてください。

EXISTS の仕組み

COLUMN_LIST を必要な列に、TABLE_NAME と OTHER_TABLE を 2 つのテーブルに、 OUTER_ALIAS と INNER_ALIAS をそれらの名前に、COLUMN_NAME をそれらを結ぶ列に、 内側の WHERE を行が関連していると言える条件に置き換えます。 SELECT 1 は慣習です。選択リストは無視されるため、SELECT 1、SELECT *、 および SELECT column はまったく同じように振る舞い、1 は何も読んでいないことを はっきり示します。 このサブクエリは相関しています。外側の行を参照しているからです。1 行あれば 「はい」と答えるのに十分なので、サーバーは最初に一致した行で止まれます。

例

  1. 一致を持つ行

6 つの言語のうち 1 つに映画があります。

  1. 一致を持たない行

NOT EXISTS は対になるもう一方で、アンチ結合を書く方法です。
残りの 5 つです。LEFT JOIN のレッスンは同じ質問に WHERE f.film_id IS NULL で答え、2 つの形は同じ行を返します。

NOT EXISTS は NOT IN が安全でない場面で安全

IN のレッスンでは、リストに NULL が含まれると NOT IN が行を まったく返さなくなることを示しています。NOT EXISTS にそのような罠はありません。 値を比較することがなく、行を数えるからです。 そのため、サブクエリが NULL になり得る列を読むときは NOT EXISTS を使って ください。NOT IN は NOT NULL と宣言された列に対しては問題ありませんが、それが 成り立たなくなった瞬間にリスクになります。

EXISTS は行を増やさない

複数の一致する行を持つテーブルへの結合は、INNER JOIN のレッスンが示すように、外側の行を一致ごとに繰り返します。EXISTS にはそれが できません。はいかいいえで答えるため、一致がいくつあっても外側の各行は 1 回だけ 現れます。 EXISTS、IN、および結合はどれも「関連する行を持つ」を表現でき、どれが最速かは データ次第です。 MySQL におけるサブクエリと JOIN の比較では、 実行計画を使ってそれらを比較しています。

まとめ

  • サブクエリが行を見つけるかどうかをテストするには EXISTS を使います。
  • 選択リストは無視されるため、内側には SELECT 1 と書きます。
  • 一致のない行には NOT EXISTS を使います。
  • サブクエリの列が NULL になり得るときは、NOT IN より NOT EXISTS を使います。
  • 結合なら起きる行の増加は起きないと考えてください。

関連項目