> ## 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 の LIKE

> MySQL の LIKE 演算子が % と _ でパターンに一致させる仕組み、それらの文字そのものに一致させる方法、そして LIKE がデフォルトで大文字と小文字を区別しない理由。

> [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 →

`=` は値全体に一致させます。`LIKE` はパターンに一致させるので、ある単語で
始まるタイトル、ある単語で終わるタイトル、特定の形をしたタイトルを求める
ことができます。

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

## LIKE の仕組み

```sql theme={null}
SELECT COLUMN_LIST
FROM TABLE_NAME
WHERE COLUMN_NAME LIKE 'PATTERN_TEXT';
```

`PATTERN_TEXT` を一致させるパターンに置き換えます。パターンは普通のテキストに
2 つの特殊文字を加えたものです。

| 文字 | 一致するもの |
| - | - |
| `%` | 任意の長さの文字の並び(まったくない場合も含む) |
| `_` | ちょうど 1 文字 |

パターン内のそれ以外の文字は、その文字自身に一致します。`%` も `_` も含まない
パターンは `=` とほぼ同じように振る舞います。両者が分かれるのは末尾の空白です。
`utf8mb4_general_ci` のような `PAD SPACE` 照合順序では、`'a ' = 'a'` は真で
`'a ' LIKE 'a'` は偽です。`NO PAD` 照合順序(すべての `utf8mb4_0900` 照合順序が
そうです)では、どちらも偽です。

## 例

### 前方一致

```sql theme={null}
SELECT title FROM film WHERE title LIKE 'ACADEMY%' ORDER BY title;
```

```text theme={null}
+------------------+
| title            |
+------------------+
| ACADEMY DINOSAUR |
+------------------+
1 row in set (0.00 sec)
```

### 後方一致

```sql theme={null}
SELECT title FROM film WHERE title LIKE '%GOLDFINGER' ORDER BY title;
```

```text theme={null}
+----------------------+
| title                |
+----------------------+
| ACE GOLDFINGER       |
| BREAKFAST GOLDFINGER |
| SILVERADO GOLDFINGER |
+----------------------+
3 rows in set (0.00 sec)
```

### 決まった文字数

`J` の後の 3 つのアンダースコアは、ちょうど 4 文字の名前を求めます。

```sql theme={null}
SELECT first_name, last_name
FROM actor
WHERE first_name LIKE 'J___'
ORDER BY first_name, last_name;
```

```text theme={null}
+------------+-------------+
| first_name | last_name   |
+------------+-------------+
| JADA       | RYDER       |
| JANE       | JACKMAN     |
| JEFF       | SILVERSTONE |
| JOHN       | SUVARI      |
| JUDE       | CRUISE      |
| JUDY       | DEAN        |
+------------+-------------+
6 rows in set (0.00 sec)
```

`JOHNNY` はリストにありません。`J___` は 4 文字に一致し、それ以上には一致
しないからです。

### 一致しない

```sql theme={null}
SELECT title FROM film WHERE title NOT LIKE 'A%' ORDER BY title LIMIT 5;
```

```text theme={null}
+---------------------+
| title               |
+---------------------+
| BABY HALL           |
| BACKLASH UNDEFEATED |
| BADMAN DAWN         |
| BAKED CLEOPATRA     |
| BALLOON HOMEWARD    |
+---------------------+
5 rows in set (0.00 sec)
```

## ここでは LIKE は大文字と小文字を区別しない

同じパターンを小文字で書いても同じ行が返ります。

```sql theme={null}
SELECT title FROM film WHERE title LIKE 'academy%' ORDER BY title;
```

```text theme={null}
+------------------+
| title            |
+------------------+
| ACADEMY DINOSAUR |
+------------------+
1 row in set (0.00 sec)
```

これは `LIKE` のルールではありません。列のルールです。列の照合順序が、2 つの
文字列を等しいとみなすかどうかを決めます。Sakila の照合順序は大文字と小文字を
区別せず、MySQL のデフォルトも同様です。
[大文字と小文字の区別](https://villagesql.com/docs/ja/tutorial/case-sensitivity.md)のレッスンでは、列を確認する
方法と、大文字と小文字を区別する一致を求める方法を示しています。

## % や \_ そのものに一致させる

検索テキスト内の `%` は、特に指定しない限りワイルドカードです。`ESCAPE` は
その直後の文字の特殊な意味を打ち消す文字を指定するので、パターンで本物の
パーセント記号を求めることができます。

```sql theme={null}
SELECT 'axxb' LIKE 'a%b' AS wildcard, 'axxb' LIKE 'a!%b' ESCAPE '!' AS literal_percent;
```

```text theme={null}
+----------+-----------------+
| wildcard | literal_percent |
+----------+-----------------+
|        1 |               0 |
+----------+-----------------+
1 row in set (0.00 sec)
```

`a%b` が `axxb` に一致したのは、`%` が `xx` を表したからです。`a!%b` は `a` と
`b` の間にパーセント記号そのものを求めましたが、`axxb` にはそれがありません。

```sql theme={null}
SELECT '50%' LIKE '50!%' ESCAPE '!' AS literal_percent;
```

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

アンダースコアも同じように働きます。

```sql theme={null}
SELECT 'a_b' LIKE 'a!_b' ESCAPE '!' AS underscore, 'axb' LIKE 'a!_b' ESCAPE '!' AS any_char;
```

```text theme={null}
+------------+----------+
| underscore | any_char |
+------------+----------+
|          1 |        0 |
+------------+----------+
1 row in set (0.00 sec)
```

データに含まれていないと確信できる文字なら、どれでも使えます。`ESCAPE` が
なければバックスラッシュが次の文字をエスケープするので、`'a\%b'` は同じ
意味になります。この近道は、サーバーの `sql_mode` に `NO_BACKSLASH_ESCAPES` が
あると使えなくなりますが、`ESCAPE` はどちらでも使えます。

## 先頭の % はコストが高い

`LIKE 'ACADEMY%'` は列のインデックスを使えます。すべての一致が同じ既知の
テキストで始まり、インデックスはソートされた順に保持されているので、サーバーは
その部分に直接飛べるからです。`LIKE '%GOLDFINGER'` には出発点がありません。
一致はどこから始まってもよいので、サーバーは列のすべての値を読み、1 つずつ
テストします。2 つのクエリに `EXPLAIN` をかけると違いが分かります。推定行数が
1 に対して 1,000 です。

1,000 本の映画では誰も気づきません。大きなテーブルでは、ルックアップとフル
スキャンの差になります。大規模にテキストの内部を検索する必要があるときは、
別の道具が適しています。
[MySQL の全文検索](https://villagesql.com/docs/ja/guides/full-text-search.md)を参照してください。

## まとめ

* 値全体ではなくパターンに一致させるには `LIKE` を使います。
* `%` は任意の長さの文字の並び、`_` はちょうど 1 文字と読みます。
* `%` や `_` そのものに一致させるには、`ESCAPE` でエスケープ文字を指定します。
* 大文字と小文字を区別するかどうかは、`LIKE` ではなく列の照合順序が決めます。
* 大きなテーブルでは先頭の `%` を避けてください。どのインデックスも検索を絞り込めません。

## 関連項目

* [REGEXP](https://villagesql.com/docs/ja/tutorial/regexp.md) — `%` と `_` では表せないパターン
* [大文字と小文字の区別](https://villagesql.com/docs/ja/tutorial/case-sensitivity.md) — 小文字のパターンが一致した理由
* [MySQL の文字列関数](https://villagesql.com/docs/ja/guides/string-functions.md) — 比較する前にテキストを整形する
* [MySQL の全文検索](https://villagesql.com/docs/ja/guides/full-text-search.md) — 大規模にテキストの内部を検索する


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