行を絞り込む:WHERE のすべて

WHERE は条件に合う行だけを残します。複数条件の優先順位、範囲やパターンの指定、NULL の扱いを確認します。

条件を組み合わせる

AND は両側が真の行を、OR はどちらかが真の行を残します。これは「支払い済みか発送済みで、かつ合計が500を超える注文」を聞いています。

1

SELECT order_number, status, total
FROM orders
WHERE (status = 'paid' OR status = 'shipped')
  AND total > 500
ORDER BY total DESC
LIMIT 20;
Planche で実行

結果 — 20 行のうち先頭 5 行

order_numberstatustotal
ORD-2025-002767shipped30906.66
ORD-2022-001901shipped28151.01
ORD-2023-001772paid26797.87
ORD-2024-001907shipped26648.91
ORD-2025-002847paid25837.57

ブラウザの別タブで Planche が開き、サンプルデータベースを読み込んだ状態でこのクエリが入ります。このページの例はどれも同じタブを使い回します。F9 を押すまで実行はされません。

括弧によって条件のまとまり方が変わります。同じ条件から括弧だけを外して実行してみてください。

2

-- The same words without the brackets. AND binds tighter than OR,
-- so this reads as: paid (any total) OR shipped-and-over-500.
SELECT order_number, status, total
FROM orders
WHERE status = 'paid' OR status = 'shipped' AND total > 500
ORDER BY total DESC
LIMIT 20;
Planche で実行

結果 — 20 行のうち先頭 5 行

order_numberstatustotal
ORD-2025-002767shipped30906.66
ORD-2022-001901shipped28151.01
ORD-2023-001772paid26797.87
ORD-2024-001907shipped26648.91
ORD-2025-002847paid25837.57

結果が変わるのは、AND が OR より先に評価されるためです。× が + より先に計算されるのと同じです。括弧がない場合、データベースは「金額を問わず支払い済み、または 発送済みかつ500超」と解釈します。そのため少額の支払い済み注文も含まれます。

いくつかの値のどれかに一致させる

同じ列を複数の値と OR で比較する場合は、IN を使えます。

3

SELECT order_number, status, total, ordered_at
FROM orders
WHERE status IN ('paid', 'shipped', 'delivered')
ORDER BY ordered_at DESC
LIMIT 20;
Planche で実行

結果 — 20 行のうち先頭 5 行

order_numberstatustotalordered_at
ORD-2025-002480shipped6333.772025-12-28 23:52:14
ORD-2025-000505delivered2276.512025-12-28 11:16:39
ORD-2025-001581delivered2645.062025-12-28 06:12:38
ORD-2025-000995delivered2584.022025-12-28 05:47:53
ORD-2025-003219delivered561.482025-12-28 03:20:37

status IN ('paid', 'shipped', 'delivered') は3つの OR と同じことを、一度で言っています。否定形は NOT IN ですが、こちらには NULL がらみの鋭い落とし穴があり、サブクエリのレッスンで1節を割いて扱います。

範囲

BETWEEN a AND b は >= a AND <= b の省略形です。両端を含みます。

4

SELECT order_number, ordered_at, total
FROM orders
WHERE ordered_at BETWEEN '2025-01-01' AND '2025-01-31 23:59:59'
ORDER BY ordered_at
LIMIT 20;
Planche で実行

結果 — 20 行のうち先頭 5 行

order_numberordered_attotal
ORD-2025-0034122025-01-01 00:18:522806.57
ORD-2025-0036162025-01-01 11:18:146955.62
ORD-2025-0015032025-01-01 23:43:345837.23
ORD-2025-0003172025-01-02 05:08:3215130.7
ORD-2025-0012982025-01-02 18:36:325045.04

パターン

LIKE はパターンと比べます。% は任意の長さの文字列、_ はちょうど1文字を表します。

5

SELECT first_name, last_name, email
FROM customers
WHERE email LIKE '%@inbox.example'
ORDER BY last_name
LIMIT 20;
Planche で実行

結果 — 20 行のうち先頭 5 行

first_namelast_nameemail
FreyaAhmedfreya.ahmed@inbox.example
HugoAhmedhugo.ahmed@inbox.example
JonasAhmedjonas.ahmed@inbox.example
KenjiAhmedkenji.ahmed@inbox.example
LiamAhmedliam.ahmed@inbox.example

値がない、ということ

この顧客のうち279人は電話番号が記録されていません。その人たちです。

6

SELECT id, first_name, last_name, phone
FROM customers
WHERE phone IS NULL
LIMIT 20;
Planche で実行

結果 — 20 行のうち先頭 5 行

idfirst_namelast_namephone
2MateoCostaNULL
9SvenSmithNULL
21LaylaFischerNULL
25FreyaNguyenNULL
28PriyaJangNULL

そして、ほとんどの人が最初に書くのがこちらです。

7

-- 279 customers have no phone number, and this finds none of them.
SELECT id, first_name, last_name, phone
FROM customers
WHERE phone = NULL;
Planche で実行

該当する行なし

0行。エラーでも警告でもなく、空のグリッドです。

NULL は値ではなく、値がないことです。だから NULL との比較はどれも真になりません。phone = NULL は「この不明な何かは、あの不明な何かと等しいか」と聞いていて、正直な答えは「不明」です。不明は真ではないので、その行は落とされます。NULL = NULL も真ではありません。使えるのは IS NULL と IS NOT NULL だけです。

ここまでで書けるもの

ひとつのテーブルに対する条件なら、ほぼ何でも書けるようになりました。残った制約は、まだ全部がひとつのテーブルの中で完結していることです。そして聞く価値のある質問は、たいていそこに収まりません。

自分で書いてみる

  1. 韓国か日本にいて、マーケティングメールを承諾している(marketing_opt_in が1)顧客を、国、次に姓の順で並べてください。

    答えを見る

    答えを見る

    SELECT first_name, last_name, country
    FROM customers
    WHERE country IN ('KR', 'JP')
      AND marketing_opt_in = 1
    ORDER BY country, last_name
    LIMIT 20;
    Planche で実行

    結果 — 20 行のうち先頭 5 行

    first_namelast_namecountry
    AishaAhmedJP
    IsabellaAhmedJP
    IsabellaBrownJP
    TheoBrownJP
    NoraChoiJP

    IN が OR をひとつ節約しています。ここでは AND がふたつの条件をつないでいるだけなので、括弧は要りません。並べ替えキーを2つ書けば、国が先、その中で姓が効きます。

  2. 2024年中の注文のうち、キャンセルまたは返金で終わったものを、古い順に。

    答えを見る

    答えを見る

    SELECT order_number, status, ordered_at
    FROM orders
    WHERE ordered_at >= '2024-01-01'
      AND ordered_at <  '2025-01-01'
      AND status IN ('cancelled', 'refunded')
    ORDER BY ordered_at
    LIMIT 20;
    Planche で実行

    結果 — 20 行のうち先頭 5 行

    order_numberstatusordered_at
    ORD-2024-002563cancelled2024-01-02 11:41:56
    ORD-2024-002814cancelled2024-01-08 06:10:29
    ORD-2024-003123refunded2024-01-10 15:59:33
    ORD-2024-003024refunded2024-01-11 19:36:33
    ORD-2024-002258refunded2024-01-12 15:43:55

    要点は半開区間です。>= '2024-01-01' AND < '2025-01-01' なら12月31日の最後の瞬間まで含めて1年分を覆えます。BETWEEN '2024-01-01' AND '2024-12-31' だと0時で切れてしまいます。