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

> MySQL の BETWEEN 演算子が範囲をテストする仕組み、両端が含まれる理由、下限を先に書かなければならない理由、および静かに誤る日付範囲。

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

`BETWEEN` は値が範囲に入るかどうかをテストします。1 組の比較の省略形であり、
日付に対して、気付きにくい間違いを人がもっともよくする句です。

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

## BETWEEN の仕組み

```sql theme={null}
SELECT COLUMN_LIST
FROM TABLE_NAME
WHERE COLUMN_NAME BETWEEN LOW_BOUND AND HIGH_BOUND;
```

`LOW_BOUND` と `HIGH_BOUND` を範囲の両端に置き換えます。

`x BETWEEN a AND b` は `x >= a AND x <= b` を意味します。範囲は両端を含み、
下限を先に書きます。

## 例

### 数値の範囲

```sql theme={null}
SELECT title, length
FROM film
WHERE length BETWEEN 60 AND 70
ORDER BY length, title
LIMIT 5;
```

```text theme={null}
+-----------------------+--------+
| title                 | length |
+-----------------------+--------+
| BUBBLE GROSSE         |     60 |
| JERSEY SASSY          |     60 |
| MOCKINGBIRD HOLLYWOOD |     60 |
| PHANTOM GLORY         |     60 |
| PITY BOUND            |     60 |
+-----------------------+--------+
5 rows in set (0.00 sec)
```

ちょうど 60 分の映画が結果に含まれており、下限が一致として数えられることが
分かります。

### 同じことを書き下したもの

```sql theme={null}
SELECT title, length
FROM film
WHERE length >= 60 AND length <= 70
ORDER BY length, title
LIMIT 5;
```

```text theme={null}
+-----------------------+--------+
| title                 | length |
+-----------------------+--------+
| BUBBLE GROSSE         |     60 |
| JERSEY SASSY          |     60 |
| MOCKINGBIRD HOLLYWOOD |     60 |
| PHANTOM GLORY         |     60 |
| PITY BOUND            |     60 |
+-----------------------+--------+
5 rows in set (0.00 sec)
```

同一の行です。`BETWEEN` が省いてくれるのは列名を 2 回書く手間だけで、それ以外は
何もありません。

### 範囲の外

```sql theme={null}
SELECT title, length
FROM film
WHERE length NOT BETWEEN 60 AND 70
ORDER BY length, title
LIMIT 5;
```

```text theme={null}
+---------------------+--------+
| title               | length |
+---------------------+--------+
| ALIEN CENTER        |     46 |
| IRON MOON           |     46 |
| KWAI HOMEWARD       |     46 |
| LABYRINTH LEAGUE    |     46 |
| RIDGEMONT SUBMARINE |     46 |
+---------------------+--------+
5 rows in set (0.01 sec)
```

`NOT BETWEEN` は下限より下と上限より上の行を残します。46 分はカタログで最も
短い映画です。

## 下限を先に書かなければならない

`BETWEEN` は両端を並べ替えてくれません。大きい値を先に渡すと、70 以上かつ 60
以下の数値を求めることになり、そのような数値はありません。

```sql theme={null}
SELECT title, length
FROM film
WHERE length BETWEEN 70 AND 60
ORDER BY length, title;
```

```text theme={null}
Empty set (0.00 sec)
```

エラーも警告もありません。一致するはずの範囲から空の結果が返ったら、まず両端の
入れ替わりを疑ってください。

## 日付に対する BETWEEN は午前 0 時で止まる

これは人が実際に時間を失うもので、列の型から始まります。

```sql theme={null}
SHOW COLUMNS FROM payment LIKE 'payment_date';
```

```text theme={null}
+--------------+----------+------+-----+---------+-------+
| Field        | Type     | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------+-------+
| payment_date | datetime | NO   |     | NULL    |       |
+--------------+----------+------+-----+---------+-------+
1 row in set (0.00 sec)
```

`payment_date` は `datetime` なので、すべての値が時刻を持ちます。時刻なしで
書いた日付は、その日の始まりの午前 0 時を意味します。

```sql theme={null}
SELECT payment_id
FROM payment
WHERE payment_date BETWEEN '2005-05-25' AND '2005-05-26'
ORDER BY payment_id;
```

```text theme={null}
+------------+
| payment_id |
+------------+
|          1 |
|        146 |
|        174 |
...
+------------+
137 rows in set (0.01 sec)
```

これは「25 日と 26 日」と読めますが、137 行を返します。同じ 2 日間を半開区間と
して求めると 311 行が返ります。

```sql theme={null}
SELECT payment_id
FROM payment
WHERE payment_date >= '2005-05-25' AND payment_date < '2005-05-27'
ORDER BY payment_id;
```

```text theme={null}
+------------+
| payment_id |
+------------+
|          1 |
|        146 |
|        174 |
...
+------------+
311 rows in set (0.00 sec)
```

上限の `'2005-05-26'` は `2005-05-26 00:00:00` になりました。26 日中に行われた
支払いはすべてその瞬間より後なので、`BETWEEN` はそのすべてを除外しました。137
行は 25 日だけのものであり、ちょうど午前 0 時の瞬間に発生した支払いがあれば、それも
含まれていたはずです。

日付範囲は `>= start AND < the day after the end` (開始日以上、終了日の翌日未満) と書いてください。この形なら列が時刻を
持つかどうかを考える必要がなく、後から列に時刻が加わっても正しいままです。

## まとめ

* 範囲には `BETWEEN` を使い、両端が含まれると考えてください。
* 逆向きの範囲は何にも一致せず、エラーも警告も出さないため、下限を先に書きます。
* `x BETWEEN a AND b` は `x >= a AND x <= b` と読んでください。
* 日付には `BETWEEN` ではなく `>= start AND < day_after_end` を使います。

## 関連項目

* [WHERE](https://villagesql.com/docs/ja/tutorial/where.md) — BETWEEN を置く句
* [演算子](https://villagesql.com/docs/ja/tutorial/operators.md) — BETWEEN が省略形となっている比較
* [IN](https://villagesql.com/docs/ja/tutorial/in.md) — 範囲ではなく値のリストをテストする
* [MySQL の日付と時刻の関数](https://villagesql.com/docs/ja/guides/date-time-functions.md) — 範囲の両端を組み立てる


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