> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL の EXISTS

> MySQL の EXISTS 演算子がサブクエリが行を見つけたかどうかをテストする仕組み、NOT EXISTS が一致のない行を一覧にする方法、および NOT IN が安全でない場面で安全な理由。

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

`EXISTS` は「このサブクエリは何かを見つけたか」という、はいかいいえの質問をします。
サブクエリが何を返したかは気にせず、行があったかどうかだけを見ます。そのため、
関連する行の有無をテストしたいが、その列は 1 つも要らないときに適した道具です。

始める前に `mysql -u root -p sakila` でクライアントを開いてください。

## EXISTS の仕組み

```sql theme={null}
SELECT COLUMN_LIST
FROM TABLE_NAME AS OUTER_ALIAS
WHERE EXISTS (
  SELECT 1 FROM OTHER_TABLE AS INNER_ALIAS
  WHERE INNER_ALIAS.COLUMN_NAME = OUTER_ALIAS.COLUMN_NAME
);
```

`COLUMN_LIST` を必要な列に、`TABLE_NAME` と `OTHER_TABLE` を 2 つのテーブルに、
`OUTER_ALIAS` と `INNER_ALIAS` をそれらの名前に、`COLUMN_NAME` をそれらを結ぶ列に、
内側の `WHERE` を行が関連していると言える条件に置き換えます。

`SELECT 1` は慣習です。選択リストは無視されるため、`SELECT 1`、`SELECT *`、
および `SELECT column` はまったく同じように振る舞い、`1` は何も読んでいないことを
はっきり示します。

このサブクエリは相関しています。外側の行を参照しているからです。1 行あれば
「はい」と答えるのに十分なので、サーバーは最初に一致した行で止まれます。

## 例

### 一致を持つ行

```sql theme={null}
SELECT l.name
FROM language AS l
WHERE EXISTS (SELECT 1 FROM film AS f WHERE f.language_id = l.language_id)
ORDER BY l.name;
```

```text theme={null}
+---------+
| name    |
+---------+
| English |
+---------+
1 row in set (0.00 sec)
```

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

### 一致を持たない行

`NOT EXISTS` は対になるもう一方で、アンチ結合を書く方法です。

```sql theme={null}
SELECT l.name
FROM language AS l
WHERE NOT EXISTS (SELECT 1 FROM film AS f WHERE f.language_id = l.language_id)
ORDER BY l.name;
```

```text theme={null}
+----------+
| name     |
+----------+
| French   |
| German   |
| Italian  |
| Japanese |
| Mandarin |
+----------+
5 rows in set (0.00 sec)
```

残りの 5 つです。[LEFT JOIN](https://villagesql.com/docs/ja/tutorial/left-join.md) のレッスンは同じ質問に
`WHERE f.film_id IS NULL` で答え、2 つの形は同じ行を返します。

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

[IN](https://villagesql.com/docs/ja/tutorial/in.md) のレッスンでは、リストに NULL が含まれると `NOT IN` が行を
まったく返さなくなることを示しています。`NOT EXISTS` にそのような罠はありません。
値を比較することがなく、行を数えるからです。

そのため、サブクエリが NULL になり得る列を読むときは `NOT EXISTS` を使って
ください。`NOT IN` は `NOT NULL` と宣言された列に対しては問題ありませんが、それが
成り立たなくなった瞬間にリスクになります。

## EXISTS は行を増やさない

複数の一致する行を持つテーブルへの結合は、[INNER JOIN](https://villagesql.com/docs/ja/tutorial/inner-join.md)
のレッスンが示すように、外側の行を一致ごとに繰り返します。`EXISTS` にはそれが
できません。はいかいいえで答えるため、一致がいくつあっても外側の各行は 1 回だけ
現れます。

`EXISTS`、`IN`、および結合はどれも「関連する行を持つ」を表現でき、どれが最速かは
データ次第です。
[MySQL におけるサブクエリと JOIN の比較](https://villagesql.com/docs/ja/guides/subqueries-vs-joins.md)では、
実行計画を使ってそれらを比較しています。

## まとめ

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

## 関連項目

* [相関サブクエリ](https://villagesql.com/docs/ja/tutorial/correlated-subqueries.md) — EXISTS が使うサブクエリの形
* [IN](https://villagesql.com/docs/ja/tutorial/in.md) — NULL の罠を持つ演算子
* [LEFT JOIN](https://villagesql.com/docs/ja/tutorial/left-join.md) — 同じ質問を結合で問うたもの
* [MySQL におけるサブクエリと JOIN の比較](https://villagesql.com/docs/ja/guides/subqueries-vs-joins.md) — オプティマイザがどの形を好むか


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.