データベースから特定の範囲に収まるデータを抽出する際、SQLのBETWEEN演算子は非常に便利で直感的な手段を提供します。
数値の範囲指定だけでなく、日付の期間検索や文字列のフィルタリングなど、実務のあらゆるシーンで活用される基本的な構文です。
本記事では、BETWEEN演算子の基本的な使い方から、実務でハマりやすい日付指定の注意点、パフォーマンスへの影響まで詳しく解説します。
SQL初心者の方はもちろん、より正確なクエリを作成したい中級者の方も、ぜひこの機会にBETWEEN演算子の挙動を正しくマスターしましょう。
BETWEEN演算子の基本的な使い方と構文
SQLのBETWEEN演算子は、指定した範囲内に値が含まれているかどうかを判定するために使用されます。
基本的な構文は、WHERE 列名 BETWEEN 開始値 AND 終了値 という形式で記述します。
この演算子の最大の特徴は、開始値と終了値の両方を「含む」という点です。
数学的な表現を用いると、「開始値 <= 対象の値 <= 終了値」という条件式を簡潔に記述していることになります。
例えば、売上金額が1,000円から5,000円の商品を抽出したい場合に、非常に読みやすいコードを書くことができます。
基本構文の記述例
具体的なコードの書き方を確認してみましょう。
以下の例では、products テーブルから価格が3,000円から7,000円の範囲にあるレコードを取得しています。
-- 価格が3,000円から7,000円の商品を取得する
SELECT
product_id,
product_name,
price
FROM
products
WHERE
price BETWEEN 3000 AND 7000;
このクエリを実行すると、価格がちょうど3,000円のデータや7,000円のデータも結果に含まれます。
product_id | product_name | price
-----------+--------------+-------
001 | マウス | 3000
005 | キーボード | 5500
009 | モニター | 7000
数値範囲の指定におけるポイント
数値に対してBETWEENを使用する場合、最も注意すべきなのは値の順番です。
BETWEEN演算子は、必ず 「BETWEEN 小さい値 AND 大きい値」 の順で記述しなければなりません。
もし BETWEEN 7000 AND 3000 のように逆の順番で記述した場合、多くのデータベース製品ではエラーにはなりませんが、結果が0件となってしまいます。
これは、内部的に「7000以上かつ3000以下」という矛盾した条件として解釈されるためです。
比較演算子との違い
BETWEEN演算子は、比較演算子である >= と <= を使って書き換えることが可能です。
以下の2つのクエリは、論理的に全く同じ結果を返します。
-- BETWEENを使用した場合
SELECT * FROM orders WHERE amount BETWEEN 100 AND 500;
-- 比較演算子を使用した場合
SELECT * FROM orders WHERE amount >= 100 AND amount <= 500;
BETWEENを使用するメリットは、可読性が高く、記述がシンプルになる点にあります。
特に複数の条件を組み合わせる複雑なWHERE句では、BETWEENを使うことでコードの見通しが格段に良くなります。
日付・時刻の範囲指定における注意点
実務でBETWEEN演算子が最も多用されるのは、日付や時刻の範囲指定です。
しかし、日付データの検索には 「時刻が含まれているかどうか」 という重大な注意点が存在します。
日付型(DATE)の場合
時刻情報を持たないDATE型の場合、BETWEENは直感通りに動作します。
例えば、2026年1月1日から2026年1月31日までのデータを取得したい場合は以下のようになります。
-- 2026年1月中のデータを取得
SELECT * FROM sales
WHERE sales_date BETWEEN '2026-01-01' AND '2026-01-31';
タイムスタンプ型(DATETIME / TIMESTAMP)の落とし穴
データに時刻が含まれている場合、終了日の指定に注意が必要です。
BETWEEN '2026-01-01' AND '2026-01-31' と記述した場合、内部的には '2026-01-31 00:00:00' として扱われることが多いです。
つまり、「1月31日の昼12時に発生したデータ」は検索結果に含まれない という事態が発生します。
この問題を回避するためには、終了日に時刻を明示するか、比較演算子を使用するのが一般的です。
-- 対策1:時刻を秒単位まで指定する
WHERE sales_at BETWEEN '2026-01-01 00:00:00' AND '2026-01-31 23:59:59';
-- 対策2:比較演算子を使用して翌日の未満を指定する(推奨)
WHERE sales_at >= '2026-01-01' AND sales_at < '2026-02-01';
特に2026年現在のモダンなシステム開発では、厳密なデータ整合性が求められるため、対策2のような「以上・未満」の組み合わせが好まれる傾向にあります。
文字列の範囲指定と並び順
BETWEEN演算子は、文字列に対しても使用することができます。
文字列に使用した場合は、辞書順(レキシカル順)で範囲が判定されます。
-- AからCで始まるユーザー名を抽出
SELECT user_name FROM users
WHERE user_name BETWEEN 'A' AND 'C';
ただし、文字列のBETWEENには特有の挙動があります。
上記の例で 'C' を終了値にした場合、'C' という一文字のデータは含まれますが、'Cat' や 'Cherry' は含まれない可能性があります。
なぜなら、辞書順では 'C' よりも 'Cat' の方が後ろに位置するためです。
文字列で特定のアルファベット範囲を網羅したい場合は、'Czzzz' のように指定するか、後方一致などを検討する必要があります。
NOT BETWEENによる範囲外の抽出
特定の範囲に「含まれない」データを取得したい場合は、NOT BETWEEN を使用します。
これは、異常値の検出や特定の期間を除外した分析を行いたい時に非常に便利です。
-- 在庫数が10個未満、または100個を超える商品を抽出
SELECT product_name, stock_count
FROM inventory
WHERE stock_count NOT BETWEEN 10 AND 100;
このクエリは、「10以上かつ100以下」の反対であるため、9以下または101以上のデータを返します。
NULL値が含まれるカラムに対してNOT BETWEENを使用する場合、NULLは「範囲内」とも「範囲外」とも判定されず、結果から除外される点に注意してください。
BETWEEN演算子のパフォーマンスとインデックス
大量のデータを扱うデータベースにおいて、クエリの実行速度は非常に重要です。
結論から言うと、BETWEEN演算子は通常、インデックスを有効に活用できます。
B-Treeインデックスが張られているカラムであれば、範囲スキャンが行われるため、高速な検索が期待できます。
比較演算子の >= AND <= とパフォーマンス面での差はほとんどありません。
型の一致が重要
インデックスを最大限に活かすためには、検索値の型をカラムの型に合わせることが不可欠です。
例えば、数値型のカラムに対して BETWEEN '100' AND '500' のように文字列で指定すると、暗黙の型変換が発生し、インデックスが使われない場合があります。
必ず BETWEEN 100 AND 500 のように、適切なデータ型で値を記述しましょう。
NULL値の扱いに関する注意点
SQLにおいてNULLは「不明な値」を意味します。
そのため、BETWEEN演算子の対象となる値がNULLであったり、開始値・終了値のいずれかにNULLが指定されたりした場合、結果は UNKNOWN となります。
WHERE句の条件が UNKNOWN になると、その行は結果に含まれません。
-- priceがNULLの行は、以下のクエリでは絶対に取得されません
SELECT * FROM products WHERE price BETWEEN 0 AND 10000;
NULL値を含めてデータを抽出したい場合は、OR price IS NULL という条件を別途追加する必要があります。
実務で役立つTips
BETWEEN演算子をより使いこなすための小技を紹介します。
1. サブクエリとの組み合わせ
開始値や終了値には、固定の値だけでなく、他のテーブルから取得した値を指定することも可能です。
-- 平均価格の前後10%の範囲にある商品を抽出
SELECT * FROM products
WHERE price BETWEEN (SELECT AVG(price) * 0.9 FROM products)
AND (SELECT AVG(price) * 1.1 FROM products);
2. 値の入れ替え対策
動的に生成されるクエリなどで、開始値と終了値のどちらが大きくなるか不明な場合があります。
PostgreSQLなどの一部のデータベースでは、BETWEEN SYMMETRIC という構文がサポートされています。
これを使えば、BETWEEN 7000 AND 3000 と書いても、自動的に小さい方を開始値として扱ってくれます。
まとめ
SQLのBETWEEN演算子は、数値や日付の範囲を直感的に指定できる非常に強力なツールです。
「開始値と終了値の両方を含む」という性質を正しく理解し、特に日付データにおける時刻の扱いに注意を払うことで、バグの少ない正確なクエリを作成できます。
また、コードの可読性を高めるだけでなく、適切にインデックスを活用することでパフォーマンスの維持も可能です。
実務においては、単に範囲を指定するだけでなく、NULL値への配慮や境界値の仕様をチーム内で共有しておくことも重要です。
今回学んだ内容を活かして、より効率的でメンテナンス性の高いSQL作成を目指しましょう。
まとめ
いかがでしたでしょうか。
SQLのBETWEEN演算子は、単なる範囲指定以上の奥深さがあることをご理解いただけたかと思います。
最後に、本記事で解説した重要なポイントを振り返ります。
- BETWEENは「開始値以上・終了値以下」として動作し、両端の値を含む。
- 必ず「BETWEEN 小さい値 AND 大きい値」の順序で記述する。
- 日付時刻型で使用する場合は、終了日の時刻(23:59:59など)を考慮しないとデータが漏れる可能性がある。
- 文字列の比較は辞書順で行われる。
- NULLが含まれる場合、結果はUNKNOWNとなり、データは抽出されない。
これらのルールを意識するだけで、データ抽出のミスを大幅に減らすことができます。
日々の業務や学習に、ぜひお役立てください。
