記事の目的
SQL の WHERE 句を使って、テーブルから「条件に合う行だけ」を取り出せるようになります。
比較演算子による基本の絞り込み、AND / OR / NOT による複数条件の組み合わせ、NULL の判定、そして範囲・リスト・あいまい検索といった頻出パターンまでを整理します。BETWEEN ・ IN ・ LIKE などの個別構文はそれぞれ専用記事へ誘導します。
記事のサンプルテーブルの前提
本記事では、説明用に次のような orders テーブルがある前提で進めます。
- id :自動採番(注文番号)
- customer_id :顧客 ID(文字列)
- amount :金額(整数。
NULLを含む可能性あり) - status :注文ステータス(
'pending'/'shipped'/'cancelled'のいずれか) - order_date :注文日(日付型)
実際の CREATE TABLE 文は別記事で扱います。本文中では次のサンプルデータがすでに入っているものとして説明します。
SELECT * FROM orders;
id | customer_id | amount | status | order_date
---+-------------+--------+-----------+-----------
1 | C001 | 1500 | shipped | 2026-01-10
2 | C002 | 800 | pending | 2026-02-05
3 | C001 | 3000 | shipped | 2026-02-15
4 | C003 | 500 | cancelled | 2026-03-01
5 | C002 | NULL | pending | 2026-03-10
最短の答え
orders から「金額 1000 以上で出荷済み(shipped)の注文」を取り出します。
- 主要な RDBMS(PostgreSQL / MySQL / SQL Server)で共通して使える基本形
SELECT id, customer_id, amount, status
FROM orders
WHERE amount >= 1000 AND status = 'shipped';実行結果は次のようになります。
id | customer_id | amount | status
---+-------------+--------+--------
1 | C001 | 1500 | shipped
3 | C001 | 3000 | shipped
- 1 つの条件だけで絞り込む(金額 1000 以上)
SELECT * FROM orders WHERE amount >= 1000;- 「OR」で複数条件のどれかを満たす
SELECT * FROM orders
WHERE status = 'pending' OR status = 'shipped';NULLの判定は=ではなくIS NULLを使う
SELECT * FROM orders WHERE amount IS NULL;ここから先は、WHERE 句の基本から、比較演算子・複数条件・NULL 判定・範囲やリストの絞り込みまでを順に解説します。
WHERE 構文の基本
WHERE 句は、SELECT / UPDATE / DELETE の中で「対象とする行を絞る」ために使います。
SELECT 列 FROM テーブル
WHERE 条件;WHEREの右側に「行ごとに真偽が決まる条件式」を書きます。- 条件式が
TRUEになった行だけが結果に含まれます。
SELECT 文で使う WHERE 句は、元のテーブルを変更せず、表示する行を絞り込みます。一方、UPDATE やDELETE で使う WHERE 句は、更新・削除の対象行を決めます。書き忘れると全行が対象になるため、UPDATE / DELETE では特に注意します(詳しくは各専用記事へ)。
SELECT 文の中での実行の順番は、書く順番( SELECT … FROM … WHERE … )とは違います。ここでは、WHERE 句の理解に必要な範囲だけを簡略化して示します。
FROM(どのテーブルから)
↓
WHERE(どの行を残すか)
↓
SELECT(どの列を取り出すか)
↓
ORDER BY(どの順に並べるか)
実際の SQL では、これに GROUP BY ・ HAVING ・ DISTINCT ・ LIMIT などの段階も加わります。詳細は各専用記事で扱います。
そのため、SELECT 句で付けた別名( SELECT amount AS price )は、同じクエリの WHERE では使えません(多くの製品でエラー)。これは混乱しやすいポイントです。
比較演算子 ──1つの条件の書き方
最も基本となる「列と値」を比較する演算子です。3製品で共通して使えます。
| 演算子 | 意味 | 例 |
|---|---|---|
= | 等しい | WHERE status = 'shipped' |
<> または != | 等しくない | WHERE status <> 'cancelled' |
> | より大きい | WHERE amount > 1000 |
>= | 以上 | WHERE amount >= 1000 |
< | より小さい | WHERE amount < 1000 |
<= | 以下 | WHERE amount <= 1000 |
- 「等しくない」は
<>と!=の両方が 3 製品とも使えますが、SQL 標準は<>です。移植性を考えるなら<>を選びます。 - 文字列リテラルはシングルクォート
'で囲みます。ダブルクォート"は多くの製品で「識別子(列名)」の意味になり、文字列ではありません。
-- 金額がちょうど 1500 の注文
SELECT * FROM orders WHERE amount = 1500;id | customer_id | amount | status | order_date
---+-------------+--------+---------+-----------
1 | C001 | 1500 | shipped | 2026-01-10
AND・OR・NOT ── 複数条件の組み合わせ
複数の条件を組み合わせるには、論理演算子 AND / OR / NOT を使います。
| 演算子 | 意味 |
|---|---|
AND | 両方の条件が真のとき真 |
OR | どちらかの条件が真のとき真 |
NOT | 条件の真偽を反転 |
優先順位 ── 括弧を恐れず使う
論理演算子の優先順位は、NOT > AND > OR の順です。これを忘れると意図と違う絞り込みになります。
-- ① 意図しない結果になりやすい例
SELECT * FROM orders
WHERE status = 'pending' OR status = 'shipped' AND amount >= 1000;
-- ② ①は次のように解釈される(AND が先)
SELECT * FROM orders
WHERE status = 'pending' OR (status = 'shipped' AND amount >= 1000);pending のものは金額に関係なく全部入ってしまいます。「ステータスが pending か shipped のどちらかで、かつ金額 1000以上」と書きたいなら、括弧で明示します。
-- 正しい意図:括弧で OR をまとめる
SELECT * FROM orders
WHERE (status = 'pending' OR status = 'shipped')
AND amount >= 1000;id | customer_id | amount | status | order_date
---+-------------+--------+---------+-----------
1 | C001 | 1500 | shipped | 2026-01-10
3 | C001 | 3000 | shipped | 2026-02-15
複雑な WHERE 句では、たとえ優先順位を正しく覚えていても、意図を明示するために括弧をつけたほうが安全です。
NOT で条件を反転する
-- キャンセル済みでない注文
SELECT * FROM orders WHERE NOT (status = 'cancelled');
-- 上は次と同じ
SELECT * FROM orders WHERE status <> 'cancelled';NOT は他の条件と組み合わせて「〜でないかつ〜」のような場面で活躍しますが、後述の NULL の挙動にも注意が必要です。
NULL の判定 ── IS NULL / IS NOT NULL
NULL は「値が不明」を表す特別な印で、通常の比較演算子では判定できません。
-- これは思った通りに動かない(amount が NULL の行はヒットしない)
SELECT * FROM orders WHERE amount = NULL;
-- これも動かない
SELECT * FROM orders WHERE amount <> NULL;NULL の判定には専用の演算子 IS NULL / IS NOT NULL を使います。
-- 金額が NULL の注文
SELECT * FROM orders WHERE amount IS NULL;id | customer_id | amount | status | order_date
---+-------------+--------+---------+-----------
5 | C002 | NULL | pending | 2026-03-10
-- 金額が NULL ではない注文
SELECT * FROM orders WHERE amount IS NOT NULL;3値論理 ── TRUE / FALSE / UNKNOWN
WHERE 句の真偽は実は3値( TRUE / FALSE / UNKNOWN )で評価されます。NULL を含む比較は UNKNOWN になり、結果に含まれません。
-- amount が NULL の行は、これでもヒットしない
SELECT * FROM orders WHERE amount >= 1000 OR amount < 1000;
-- → NULL >= 1000 は UNKNOWN、NULL < 1000 も UNKNOWN
-- → UNKNOWN OR UNKNOWN は UNKNOWN なので結果に含まれないNULL を含めたい場合は、明示的に条件を足します。
SELECT * FROM orders
WHERE amount >= 1000 OR amount < 1000 OR amount IS NULL;範囲・リスト・あいまいの絞り込み
WHERE の中で頻出する3つのパターンは、それぞれ専用の構文があり、別記事で深掘りします。本記事では「どんな書き方ができるか」の入口だけ示します。
範囲:BETWEEN
「ある値からある値までの範囲」は BETWEEN A AND B で書きます(A と B を含む)。
-- 金額が 1000 以上 3000 以下
SELECT * FROM orders WHERE amount BETWEEN 1000 AND 3000;AND で書いた WHERE amount >= 1000 AND amount <= 3000 と意味は同じです。詳しくは別記事「SQL BETWEEN の使い方|範囲指定で抽出する(数値・日付)」へ。
リスト:IN / NOT IN
「複数の候補のいずれかに一致するか」は IN (…) で書きます。
-- ステータスが pending または shipped
SELECT * FROM orders WHERE status IN ('pending', 'shipped');OR で書いた WHERE status = 'pending' OR status = 'shipped' と意味は同じですが、候補が増えるほど IN のほうが見やすくなります。詳しくは別記事「SQL IN / NOT IN の使い方|複数値・サブクエリでの絞り込み」へ。
あいまい:LIKE
「文字列を部分一致で検索」は LIKE を使います。
-- 顧客 ID が C00 で始まる注文
SELECT * FROM orders WHERE customer_id LIKE 'C00%';詳しくは別記事「SQL LIKE 句のあいまい検索|% _ エスケープと実例」へ。
3つを組み合わせる
実務では、これらを AND で組み合わせて1つの WHERE に書きます。
-- ステータスが shipped または pending で、金額 1000〜3000、2026年に発生した注文
SELECT * FROM orders
WHERE status IN ('shipped', 'pending')
AND amount BETWEEN 1000 AND 3000
AND order_date >= '2026-01-01' AND order_date < '2027-01-01';落とし穴・注意点
NULL と NOT IN の罠
NOT IN (…) のリストに NULL が含まれていると、NULL との比較が UNKNOWN になり、何もヒットしなくなることがあります。
-- サブクエリの結果に NULL が混じっていると、結果が空になりがち
SELECT * FROM orders
WHERE customer_id NOT IN (SELECT customer_id FROM blacklist);サブクエリ側で WHERE customer_id IS NOT NULL を入れる、NOT EXISTS に書き換える、などの対策が必要です。詳細は別記事で扱います。
文字列リテラルはシングルクォート
-- 正しい
WHERE status = 'shipped'
-- これは多くの製品でエラー(識別子と解釈される)
WHERE status = "shipped文字列はシングルクォート ' で囲みます。ダブルクォート " は、PostgreSQL や SQL Server では「識別子(列名・テーブル名)の引用符」として扱われ、文字列にはなりません。
MySQL では SQL モードの設定によって挙動が変わり、既定では文字列としても受け付けますが、ANSI_QUOTES モードでは識別子扱いになります。移植性を考えるなら、文字列には常にシングルクォートを使うのが安全です。
文字列の大文字小文字は製品差が大きい
WHERE status = 'SHIPPED' がヒットするかどうかは、製品と照合順序の設定で変わります。
- PostgreSQL:原則として区別する
- MySQL:照合順序による。既定では区別しない設定が多い
- SQL Server:照合順序による。既定では区別しないことが多い
詳しくは別記事を参照。
インデックスが効く条件・効かない条件
WHERE は実行計画に直結します。インデックスが効きやすいのは次のような条件です。
- 等価比較:
列 = 値 - 前方一致
LIKE:列 LIKE '値%' - 範囲比較:
列 BETWEEN A AND B/列 >= A AND 列 <= B
逆に、列側に関数や型変換がかかる書き方ではインデックスが使われにくくなる傾向があります。
- 列に関数をかける:
WHERE LOWER(name) = 'sato' - 列を明示的に型変換する:
WHERE CAST(amount AS CHAR) = '100' - 中間一致
LIKE:WHERE name LIKE '%佐藤%'
比較する値は、できるだけ列の型に合わせて書きます(数値列なら数値リテラル、文字列列なら文字列リテラル)。件数が大きいテーブルで遅いと感じたら、EXPLAIN (PostgreSQL / MySQL)や実行プラン表示(SQL Server)で確認します。
まとめ
WHERE 句は SQL の絞り込みの基本ですが、比較演算子・AND / OR / NOT の優先順位(括弧で意図を明示)・NULL の判定( IS NULL を使う)の 3 点を押さえ、範囲・リスト・あいまいは専用記事で深掘りすれば、現場の絞り込みはほとんど書けるようになります。
