BETWEEN 述語の使い方
shain社員
| name | salary |
|---|---|
| 中村 | 530000 |
| 井上 | 505000 |
| 佐藤 | 720000✕ |
| 加藤 | 610000✕ |
| … | |
salary BETWEEN 400000 AND 530000範囲に入った行
| name | salary |
|---|---|
| 中村 | 530000 |
| 井上 | 505000 |
| … | |
WHERE salary BETWEEN 400000 AND 530000
- 取り消し線= 条件に合わないので結果に出てこない行
- 社員 18 行 → 範囲に入った行 12 行(6 行が消えます)
18 行のうち 12 行が残ります。上限ちょうどの 530000 の行が残っているのが見えます(両端を含むため)。
`BETWEEN` は「以上かつ以下」をひとまとめに書く述語です。 いちばん大事な事実は 両端を含むことと、上下を逆に書くと 0 行になることです。そして時刻を持つ列に使うと、最終日のデータが落ちます。
この書き方が使えない製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database
未確認: IBM Db2
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
01両端を含む(以上かつ以下)
結論: `列 BETWEEN a AND b` は `列 >= a AND 列 <= b` と完全に同じ意味です。
つまり a も b も範囲に入ります。「a より大きく b より小さい」ではありません。ここを取り違えると、境界の 1 件がずれます。
BETWEEN を使う利点は、列名を 1 回しか書かなくてよいことです。列名が長いときや式を書くときに効きます。逆に「以上かつ未満」にしたいときは BETWEEN では書けないので、>= と < を並べます。
読みやすさのために BETWEEN を選び、境界の扱いが違うときは素直に比較演算子を並べる、と使い分けてください。
SELECT name, salaryどの列を出すかFROM shainどの表を見るかWHERE salary BETWEEN 400000 AND 530000400000 以上かつ 530000 以下ORDER BY salary並び順
小さいほうを先、大きいほうを後に書きます。順番には意味があります(次の節)。
SELECT name, salary
FROM shain
WHERE salary BETWEEN 400000 AND 530000
ORDER BY salary;| name | salary |
|---|---|
| 渡辺 | 400000 |
| 松本 | 421000 |
| 大野 | 432000 |
| 小林 | 445050 |
| 斎藤 | 455000 |
| 吉田 | 468000 |
| 高橋 | 480000 |
| 井上 | 505000 |
| 山本 | 512000 |
| 田中 | 520000 |
| 伊藤 | 530000 |
| 中村 | 530000 |
(12 行)
12 行です。先頭の渡辺はちょうど 400000、末尾の中村と伊藤はちょうど 530000 で、どちらも残っています。
SELECT name, salary
FROM shain
WHERE salary >= 400000 AND salary <= 530000
ORDER BY salary;| name | salary |
|---|---|
| 渡辺 | 400000 |
| 松本 | 421000 |
| 大野 | 432000 |
| 小林 | 445050 |
| 斎藤 | 455000 |
| 吉田 | 468000 |
| 高橋 | 480000 |
| 井上 | 505000 |
| 山本 | 512000 |
| 田中 | 520000 |
| 伊藤 | 530000 |
| 中村 | 530000 |
(12 行)
同じ 12 行です。BETWEEN は書き方が短くなるだけで、意味は変わりません。
02⚠️ よくある間違い:上下を逆に書くと 0 行になる
結論: `BETWEEN 大きい値 AND 小さい値` と書くと、エラーにならずに 0 行が返ります。
BETWEEN 530000 AND 400000 は salary >= 530000 AND salary <= 400000 に展開されます。両方を満たす値は存在しないので、必ず 0 行です。
エラーが出ないのが厄介な点です。 「該当なし」という結果は一見もっともらしいので、変数で範囲を渡している場合などは、値の入れ違いに長く気づけません。
範囲を変数から組み立てるときは、渡す前に大小を揃えるか、>= と <= を明示的に並べて書いてください。
SELECT name, salary
FROM shain
WHERE salary BETWEEN 530000 AND 400000;| name | salary |
|---|
(0 行)
1 行も返りません。該当者がいないのではなく、条件そのものが成立していません。
03日付にも文字列にも使える
結論: 大小を比べられるものなら何にでも使えます。 日付でも文字列でも構いません。
日付の期間指定は BETWEEN のいちばん多い使い道です。ただしその列が日付だけを持つのか、時刻も持つのかで結果が変わります(次の節)。
文字列にも使えますが、比較の順序は五十音順ではなく文字コード順です。日本語の文字列に範囲指定を使うと、直感と違う行が入ってきます。文字列の範囲指定は避けるほうが無難です。
SELECT name, hired_on
FROM shain
WHERE hired_on BETWEEN DATE '2020-01-01' AND DATE '2020-12-31'
ORDER BY hired_on;| name | hired_on |
|---|---|
| 中村 | 2020-04-01 |
| 井上 | 2020-10-01 |
(2 行)
2 行です。この表の hired_on は時刻を持たない日付型なので、12/31 が正しく含まれます。
⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表
SELECT busho_name
FROM busho
WHERE busho_name BETWEEN '営' AND '管'
ORDER BY busho_id;| busho_name |
|---|
| 営業 |
| 基盤 |
| 法務 |
(3 行)
営業・基盤・法務が返ります。五十音では「基盤」も「法務」も範囲の外に思えますが、文字コード上はこの 3 つが範囲に入ります。
04⚠️ よくある間違い:時刻を持つ列では最終日が落ちる
結論: 時刻を持つ列に `BETWEEN '開始日' AND '終了日'` と書くと、終了日の 00:00:00 より後のデータが全部落ちます。
2020-12-31 とだけ書くと、多くの製品はこれを 2020-12-31 00:00:00 として扱います。したがって 12/31 の午前 10 時に登録されたデータは、その時点より後なので範囲に入りません。1 日ぶん近くのデータが黙って消えることになります。
この表の hired_on は時刻を持たない日付型なので問題は起きませんが、注文日時・更新日時のような列では必ず起きます。
対処は「翌日の 0 時未満」で書くことです。
- ✗
BETWEEN DATE '2020-01-01' AND DATE '2020-12-31' - ○
>= DATE '2020-01-01' AND < DATE '2021-01-01'
この形なら、列が日付でも日時でも同じ結果になります。期間指定は `>=` と `<` で書くのを既定にしてください。
SELECT TIMESTAMP '2020-12-31 10:00'
BETWEEN TIMESTAMP '2020-01-01'
AND TIMESTAMP '2020-12-31' AS hairu;| hairu |
|---|
| false |
(1 行)
false が返ります。終了日が 12/31 の 0 時ちょうどとして扱われるためです。
SELECT name, hired_on
FROM shain
WHERE hired_on >= DATE '2020-01-01'
AND hired_on < DATE '2021-01-01'
ORDER BY hired_on;| name | hired_on |
|---|---|
| 中村 | 2020-04-01 |
| 井上 | 2020-10-01 |
(2 行)
2 行で、BETWEEN で書いたときと同じ結果です。列の型が時刻付きに変わっても、この書き方なら結果は変わりません。
⚠️ この書き方は SQLite / SQL Server / Oracle Database では使えません(DATE 'YYYY-MM-DD' の日付リテラル)。製品ごとの対応表
05⚠️ よくある間違い:NOT BETWEEN は NULL の行を消す
結論: `NOT BETWEEN` を使うと、その列が NULL の行が黙って消えます。
NOT BETWEEN は NOT (列 >= a AND 列 <= b) に展開されます。列が NULL なら比較は unknown になり、否定しても unknown のままなので、WHERE を通れません。
NOT IN のときとまったく同じ仕組みです。「範囲の外」を出したいのに件数が足りないときは、その列に NULL があるかを確かめてください。
NULL も含めたいなら OR 列 IS NULL を明示的に足します。
SELECT name, busho_id
FROM shain
WHERE busho_id NOT BETWEEN 2 AND 3
ORDER BY shain_id;| name | busho_id |
|---|---|
| 鈴木 | 1 |
| 加藤 | 5 |
| 吉田 | 5 |
| 井上 | 7 |
| 木村 | 7 |
| 清水 | 4 |
| 斎藤 | 4 |
| 山本 | 4 |
(8 行)
8 行です。所属が 2 でも 3 でもない社員は本来 10 人いますが、渡辺と大野(所属未設定)が落ちています。
SELECT name, busho_id
FROM shain
WHERE busho_id NOT BETWEEN 2 AND 3
OR busho_id IS NULL
ORDER BY shain_id;| name | busho_id |
|---|---|
| 鈴木 | 1 |
| 加藤 | 5 |
| 吉田 | 5 |
| 井上 | 7 |
| 木村 | 7 |
| 清水 | 4 |
| 斎藤 | 4 |
| 山本 | 4 |
| 渡辺 | NULL |
| 大野 | NULL |
(10 行)
10 行になりました。増えた 2 行が所属未設定の社員です。
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
- 比較演算子BETWEEN は比較演算子 2 つの短縮形です。
- AND / OR / NOTNOT BETWEEN で行が消える理由は 3 値論理そのものです。
- IN 述語「範囲」ではなく「このどれか」で絞るときに使います。
- 日付関数(練習問題)日付の期間指定をもう少し詳しく扱います。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 比較関数と演算子(BETWEEN)一次情報・確認 2026-08-03
- PostgreSQL 18 マニュアル: 日付/時刻型一次情報・確認 2026-08-03
- MySQL 8.4 リファレンスマニュアル: 比較関数と演算子(BETWEEN)一次情報・確認 2026-08-03