中学社会667106 views
数学講師2852771 views
小学理科717236 views
高校倫理1433119 views
Computer365120 views
ヒストリア284143 views
MathPython491378 views
高校国語785655 views
教育148875 views
世界の国560595 views
Help
Tools

English

MySQL の BETWEEN で範囲を指定する

WHERE 句で「100 以上 500 以下」のような範囲条件を書くとき、>=<= を AND で繋ぐ方法がまず思い浮かびます。これでも動作に問題はありませんが、BETWEEN を使えば同じ意味をより簡潔に表現できます。

BETWEEN の基本構文

BETWEEN は「値が指定した範囲内にあるか」を判定する演算子です。

SELECT * FROM products
WHERE price BETWEEN 1000 AND 5000;

このクエリは price が 1000 以上かつ 5000 以下の行を返します。BETWEEN は両端の値を含む(閉区間)という点が重要です。上のクエリは次の書き方とまったく同じ意味になります。

SELECT * FROM products
WHERE price >= 1000 AND price <= 5000;
BETWEEN を使う場合

WHERE price BETWEEN 1000 AND 5000 のように 1 行で書ける。カラム名を繰り返さなくてよい。

比較演算子を使う場合

WHERE price >= 1000 AND price <= 5000 のように書く。範囲の開閉(以上/超過)を細かく制御できる。

どちらを使うかは好みの問題でもありますが、「以上かつ以下」の閉区間を表すなら BETWEEN のほうが意図が明確で読みやすいでしょう。

両端を含むことの確認

BETWEEN が閉区間であることは、見落とされがちなポイントです。具体例で確認してみましょう。

SELECT * FROM scores
WHERE point BETWEEN 80 AND 100;

このクエリでは point が 80 の行も 100 の行も結果に含まれます。「80 より大きく 100 未満」のような半開区間を表現したい場合は、BETWEEN ではなく比較演算子を使う必要があります。

SELECT * FROM scores
WHERE point > 80 AND point < 100;

SQL 標準では BETWEEN は閉区間と定められており、MySQL もこれに従っています。開区間や半開区間を BETWEEN で表現する方法はないため、境界値の扱いが重要な場面では比較演算子を明示的に使うほうが安全です。

><>=<= のように 2 つの値の大小関係を判定する演算子のこと。

日付の範囲検索

BETWEEN が最も活躍するのは日付の範囲検索です。「先月の注文だけ取得したい」「2024 年のデータを抽出したい」といった要件は日常的に発生します。

SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';

DATE 型のカラムに対して文字列リテラルで日付を指定しています。MySQL は 'YYYY-MM-DD' 形式の文字列を自動的に日付として解釈するため、この書き方で問題ありません。

ただし、DATETIME 型のカラムで BETWEEN を使う場合は注意が必要です。

SELECT * FROM orders
WHERE created_at BETWEEN '2024-01-01' AND '2024-01-31';

このクエリで created_at が DATETIME 型だと、'2024-01-31''2024-01-31 00:00:00' として解釈されます。つまり、1 月 31 日の午前 0 時ちょうどの行は含まれますが、'2024-01-31 15:30:00' のような午後のデータは取得できません。

DATE 型の場合

BETWEEN ‘2024-01-01’ AND ‘2024-01-31’ で 1 月の全日が正しく取得できる。時刻の概念がないため境界の問題が起きない。

DATETIME 型の場合

終了日を ‘2024-01-31 23:59:59’ にするか、BETWEEN を使わず created_at < ‘2024-02-01’ と書く必要がある。

DATETIME 型での範囲検索は、BETWEEN よりも比較演算子を使ったほうがミスを防ぎやすいかもしれません。

SELECT * FROM orders
WHERE created_at >= '2024-01-01'
  AND created_at < '2024-02-01';

「開始日以上、翌月初日未満」と書けば、1 月 31 日の 23:59:59 まで漏れなく取得できます。秒の端数(マイクロ秒)が存在する場合でも安全な書き方です。

NOT BETWEEN で範囲外を取得する

BETWEEN の否定形として NOT BETWEEN を使えば、範囲外の行を取得できます。

SELECT * FROM products
WHERE price NOT BETWEEN 1000 AND 5000;

このクエリは price が 1000 未満、または 5000 を超える行を返します。境界値の 1000 と 5000 は結果に含まれません。NOT BETWEEN は次の書き方と同じ意味です。

SELECT * FROM products
WHERE price < 1000 OR price > 5000;

範囲外を条件にする場面は範囲内ほど多くありませんが、異常値の検出や除外条件の指定で役に立ちます。

文字列に対する BETWEEN

BETWEEN は数値や日付だけでなく、文字列に対しても使えます。文字列の場合は辞書順(照合順序に基づく順序)で比較されます。

SELECT * FROM users
WHERE name BETWEEN 'A' AND 'M';

このクエリはアルファベット順で A から M の範囲に入る name を持つ行を返します。ただし、文字列での BETWEEN は照合順序によって挙動が変わるため、直感に反する結果になることがあります。

文字列に BETWEEN を使う

照合順序に依存した比較が行われる

大文字・小文字の扱いが環境によって異なる

たとえば、utf8mb4_general_ci(大文字小文字を区別しない照合順序)では 'a''A' は同じものとして扱われますが、utf8mb4_bin では異なる値として比較されます。文字列に BETWEEN を使う場合は、テーブルの照合順序を把握しておく必要があるでしょう。

BETWEEN とインデックス

BETWEEN は範囲検索ですが、インデックスとの相性は良好です。対象カラムに B-Tree インデックスが張られていれば、MySQL はインデックスの範囲スキャンを使って効率的にデータを絞り込みます。

-- price カラムにインデックスがある場合
SELECT * FROM products
WHERE price BETWEEN 1000 AND 5000;

このクエリは B-Tree の構造を利用して、1000 以上 5000 以下のリーフノードだけを走査します。フルテーブルスキャンと比べると、対象範囲が狭いほど大きな速度差が出ます。

ただし、BETWEEN を複数カラムに対して AND で繋いだ場合、複合インデックスの利用効率が下がることがあります。EXPLAIN で実行計画を確認し、意図したインデックスが使われているか検証する習慣をつけておくとよいでしょう。