WHEREと条件|テーブル・SELECT・条件抽出
このページはプロモーション(広告)を含みます。
テーブル・SELECT・条件抽出(初級・読む25分+演習35分)
この授業のゴール
- WHERE と比較演算子(=、<>、>=、<)で、必要な行だけを取り出せる
- AND と OR が混ざる条件で、評価順(ANDが先)を理解し、括弧で意図を明示できる
- 期間を「以上〜未満」の半開区間で書き、月初・月末の境界を取りこぼさない
- IN・BETWEEN・LIKE を使い分け、結果の行数を元の表と照合できる
仕事でどう使うか
WHERE は、どの行を結果に入れるかを決める条件です。ここを誤ると、「4月の売上」に3月や5月の注文が混ざったり、取消注文が入ったりして、報告する数字そのものが変わります。
| 路線 | この授業の使いどころ |
|---|---|
| DS(データサイエンティスト) | 分析対象の期間・状態を条件で固定する。「4月・支払済み」など対象を明記する |
| ML(機械学習エンジニア) | 学習期間と評価期間を条件で分ける。期間の境界がずれると、未来の情報が学習に混ざる |
| DX(DX推進・AI企画) | KPI定義書の「集計対象」を、そのままWHERE条件に翻訳する。仕様書と条件の対応を確認できる |
| RS(研究者) | 採択基準(対象者の条件)を条件式で明記し、再現できる形にする |
実務では「期間」「状態(取消・返金)」「チャネル」など複数の条件を組み合わせます。そのとき、ANDとORの優先順位と期間の境界が、最も多い誤りの原因です。
前提
次の言葉を使います。不安があれば先に戻ってください。
- SELECT で列を選ぶ、1行の単位 → テーブルと1行の単位、SELECTと列
- 論理(かつ・または・否定) → 真偽とAND・OR・NOT
- NULL(値がない印)は、条件ではやっかいな性質があります。本授業の最後に触れ、詳しくは NULLと3値論理 で学びます。
この授業では、SELECTと列 と同じ注文表 orders(8行)を使います。
身近な状況:「4月の支払済み注文」は何件?
経理から「4月の支払済み注文の件数と注文IDがほしい」と頼まれました。注文表 orders(1行=注文1件)の内容は次のとおりです。
| order_id | order_date | status | channel | amount |
|---|---|---|---|---|
| 1 | 2025-03-31 | paid | web | 3000 |
| 2 | 2025-04-01 | paid | app | 1200 |
| 3 | 2025-04-01 | cancelled | web | 2500 |
| 4 | 2025-04-10 | paid | store | 0 |
| 5 | 2025-04-15 | refunded | app | 1800 |
| 6 | 2025-04-20 | paid | web | NULL |
| 7 | 2025-04-30 | paid | web | 1200 |
| 8 | 2025-05-01 | paid | app | 4000 |
目で見ると、4月の支払済みは注文2、4、6、7の4件です。注文1は3月末、注文8は5月初めで期間の外、注文3は取消、注文5は返金で状態が違います。
3月31日と5月1日の注文が、期間の境界ぎりぎりに置かれているのは意図的です。条件を書くとき、境界のデータが入るか入らないかを、自分で確かめる習慣が必要です。
直感的な説明:行にふるいをかける
WHERE はふるいです。表の各行を1行ずつ条件に通し、真(条件に合う)になった行だけが残ります。
- ふるいは1行ずつ独立に判定します。他の行との比較はしません。
- 条件を複数つなぐと、ふるいが重なります。
ANDは「両方通る行だけ」、ORは「どちらかを通る行」。 - ふるいにかけても、列は減りません。列を減らすのは SELECT で、行を減らすのが WHERE です。
SQLは、基本的に次の順序で処理します。
FROM表を決めるWHERE行を絞るSELECT列を選ぶ
表を決めたあとに行を絞り、最後に列を選ぶ、と覚えておくと、「WHERE で SELECT の別名を使えるか」といった疑問が整理できます(SQLiteでは使えますが、他のデータベースでは使えないことが多いので、別名は WHERE に使わないのが安全です)。
正確な定義:比較演算子・AND/OR・半開区間
比較演算子:
| 書き方 | 意味 | 備考 |
|---|---|---|
= |
等しい | 文字列は 'paid' のように一重引用符で囲む |
<>(または !=) |
等しくない | NULLには効かない(NULLと3値論理) |
>、>=、<、<= |
大小 | 文字列は辞書順、日付文字列 'YYYY-MM-DD' は日付順 |
IN ('a','b') |
リストのどれかと等しい | = 'a' OR = 'b' と同じ |
BETWEEN a AND b |
a以上b以下(両端を含む) | 日時が混ざると取りこぼしやすい |
LIKE 'SP%' |
パターン一致。% は任意の文字列 |
大文字小文字の扱いは方言による |
AND と OR の優先順位:AND は OR より先に評価されます(掛け算が足し算より先、と同じ)。
$$A \land B \lor C = (A \land B) \lor C$$
ここで $\land$ は「かつ(AND)」、$\lor$ は「または(OR)」です。たとえば status = 'paid' AND channel = 'web' OR channel = 'app' は、「(支払済み かつ web) または (app)」と読まれます。意図が「支払済み かつ (web または app)」なら、括弧が必須です。
半開区間:期間は「以上(>=)開始日、未満(<)翌期間の開始日」で書きます。4月なら
$$\text{'2025-04-01'} \le \text{order\_date} < \text{'2025-05-01'}$$
終了日を <= '2025-04-30' と書く方法は、時刻付きのデータ('2025-04-30 18:00:00')で4月30日の注文を取りこぼします。< '2025-05-01' なら、日付だけのデータでも時刻付きでも正しく動きます(型・日付・式 で詳しく扱います)。
段階付き例題:4月の支払済み注文を抽出し、検算する
問題:4月(2025-04-01以上2025-05-01未満)の支払済み注文のID・日付・金額を、IDの昇順で出す。
ステップ1:条件を言葉にする。「状態が paid」かつ「日付が4月」。
ステップ2:条件を式にする。状態は status = 'paid'。日付は半開区間で order_date >= '2025-04-01' AND order_date < '2025-05-01'。3つの条件はすべて AND でつなぐ。
ステップ3:実行する。
-- db: none
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
order_date TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
channel TEXT NOT NULL,
amount INTEGER,
coupon_code TEXT
);
INSERT INTO orders VALUES
(1,101,'2025-03-31','paid','web',3000,NULL),
(2,102,'2025-04-01','paid','app',1200,'SPRING'),
(3,101,'2025-04-01','cancelled','web',2500,NULL),
(4,103,'2025-04-10','paid','store',0,NULL),
(5,104,'2025-04-15','refunded','app',1800,'SPRING'),
(6,102,'2025-04-20','paid','web',NULL,NULL),
(7,105,'2025-04-30','paid','web',1200,''),
(8,103,'2025-05-01','paid','app',4000,'VIP');
SELECT order_id, order_date, amount
FROM orders
WHERE status = 'paid'
AND order_date >= '2025-04-01'
AND order_date < '2025-05-01'
ORDER BY order_id;
ステップ4:結果を読む。注文2、4、6、7の4行です。注文1(3月31日)と注文8(5月1日)は期間外、注文3(取消)と注文5(返金)は状態が違うので除かれます。
ステップ5:目視で検算する。元の8行を見て、4月の日付は2〜7の6件。そのうち paid は3(取消)と5(返金)を除く4件。結果と一致します。
ステップ6:金額列の意味を確認する。結果には金額が 1200、0、NULL、1200 があります。注文4は0円(無料)、注文6は未記録(NULL)です。この4件の金額の合計は 2400 になりますが、これは注文6を含まない合計です(SUM はNULLを無視します)。「4件の売上合計」と報告する前に、未記録の1件があることを併記します。
操作して理解する:ANDとORの優先順位と、境界の確認
次の3つのSQLを、実行する前に結果を予想してから確かめてください。
-- db: none
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
order_date TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
channel TEXT NOT NULL,
amount INTEGER,
coupon_code TEXT
);
INSERT INTO orders VALUES
(1,101,'2025-03-31','paid','web',3000,NULL),
(2,102,'2025-04-01','paid','app',1200,'SPRING'),
(3,101,'2025-04-01','cancelled','web',2500,NULL),
(4,103,'2025-04-10','paid','store',0,NULL),
(5,104,'2025-04-15','refunded','app',1800,'SPRING'),
(6,102,'2025-04-20','paid','web',NULL,NULL),
(7,105,'2025-04-30','paid','web',1200,''),
(8,103,'2025-05-01','paid','app',4000,'VIP');
-- (1) 括弧なし:AND が先
SELECT order_id FROM orders
WHERE status = 'paid' AND channel = 'web' OR channel = 'app'
ORDER BY order_id;
-- (2) 括弧あり:意図どおり「支払済み かつ (web または app)」
SELECT order_id FROM orders
WHERE status = 'paid' AND (channel = 'web' OR channel = 'app')
ORDER BY order_id;
-- (3) BETWEEN は両端を含む
SELECT order_id FROM orders
WHERE order_date BETWEEN '2025-04-01' AND '2025-04-30'
ORDER BY order_id;
答えと読み方:
- (1) 注文 1、2、5、6、7、8。「(paid かつ web) または app」なので、取消ではなく返金の注文5(app)も入ります。
- (2) 注文 1、2、6、7、8。返金の注文5は paid ではないので除かれます。(1)との差は注文5の1件です。
- (3) 注文 2、3、4、5、6、7。日付が文字列のみなので、4月1日〜4月30日の両端が入ります。
(1) と (2) の差が、「括弧を付けるか否か」で生じる誤りの典型です。ANDとORを混ぜたら、必ず括弧を付けるルールにしましょう。
試してみよう:(1) の条件を channel = 'app' OR channel = 'web' AND status = 'paid' に並べ替えても結果は同じです。AND が先に評価されるため、書く順番は関係しません。
発展:NULLを含む列への条件と、BETWEENの落とし穴
NULLを含む列への否定条件:coupon_code <> 'SPRING' は「クーポンがSPRINGでない注文」のつもりで書いても、本文のデータでは注文7(空文字)と8(VIP)の2件だけが返り、クーポンなし(NULL)の注文1、3、4、6は返りません。NULLとの比較は「真」にならないためです。「クーポンなしも含めたい」なら coupon_code IS NULL OR coupon_code <> 'SPRING' と書きます(NULLと3値論理 で詳しく学びます)。
BETWEEN と時刻:BETWEEN '2025-04-01' AND '2025-04-30' は、'2025-04-30 18:30:00' のような値を含みません(文字列として '2025-04-30 18:30:00' は '2025-04-30' より大きいため)。日付型のみのデータでは問題が表に出ないため、データの形式が変わったとき(システム更新で時刻付きになったとき)に、静かに数字が減ります。半開区間にしておくと、この変更に強くなります。
IN とサブクエリ:WHERE customer_id IN (SELECT ...) のように、IN の中に別の問い合わせを書くこともできます(「サブクエリ」(有料版))。リストにNULLが含まれる NOT IN は想定外の結果になるため、NULLと3値論理 で扱います。
LIKE の注意:LIKE 'SP%' は先頭が SP で始まる文字列に一致します。% が先頭にあると(LIKE '%ING')、索引(検索を速くする仕組み)が使えず、大きな表では遅くなります。大文字小文字の扱いもデータベースによって異なります。
よくある失敗
失敗1:OR を括弧なしで混ぜて、対象外の行が入る
依頼:「支払済みで、チャネルが web または app の注文」。
-- db: none
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
order_date TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
channel TEXT NOT NULL,
amount INTEGER,
coupon_code TEXT
);
INSERT INTO orders VALUES
(1,101,'2025-03-31','paid','web',3000,NULL),
(2,102,'2025-04-01','paid','app',1200,'SPRING'),
(3,101,'2025-04-01','cancelled','web',2500,NULL),
(4,103,'2025-04-10','paid','store',0,NULL),
(5,104,'2025-04-15','refunded','app',1800,'SPRING'),
(6,102,'2025-04-20','paid','web',NULL,NULL),
(7,105,'2025-04-30','paid','web',1200,''),
(8,103,'2025-05-01','paid','app',4000,'VIP');
-- 誤り:AND が先に評価される
SELECT order_id, status, channel FROM orders
WHERE status = 'paid' AND channel = 'web' OR channel = 'app'
ORDER BY order_id;
注文5(refunded・app)が入ります。「paid かつ web」または「app」と読まれたためです。直し方:status = 'paid' AND (channel = 'web' OR channel = 'app')、または status = 'paid' AND channel IN ('web', 'app') と書く。件数を元の表で目視確認する。
失敗2:BETWEEN や <= で月末・月初の境界を誤る
依頼:「4月の注文」。担当者が BETWEEN '2025-04-01' AND '2025-05-01' と書いたとします(5月1日を含めてしまった例)。
-- db: none
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
order_date TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
channel TEXT NOT NULL,
amount INTEGER,
coupon_code TEXT
);
INSERT INTO orders VALUES
(1,101,'2025-03-31','paid','web',3000,NULL),
(2,102,'2025-04-01','paid','app',1200,'SPRING'),
(3,101,'2025-04-01','cancelled','web',2500,NULL),
(4,103,'2025-04-10','paid','store',0,NULL),
(5,104,'2025-04-15','refunded','app',1800,'SPRING'),
(6,102,'2025-04-20','paid','web',NULL,NULL),
(7,105,'2025-04-30','paid','web',1200,''),
(8,103,'2025-05-01','paid','app',4000,'VIP');
-- 誤り:5月1日の注文8が入る
SELECT order_id, order_date FROM orders
WHERE order_date BETWEEN '2025-04-01' AND '2025-05-01'
ORDER BY order_id;
-- 正しい:半開区間
SELECT order_id, order_date FROM orders
WHERE order_date >= '2025-04-01' AND order_date < '2025-05-01'
ORDER BY order_id;
誤りの結果は注文2〜8の7件、正しい結果は注文2〜7の6件です。BETWEEN は両端を含むため、終了側に翌月の1日を書くと翌月の1日が混ざります。直し方:期間は常に「>= 開始日 AND < 翌期間の開始日」で書く。
失敗3:NULLを含む列の大小条件で、NULLの行を取りこぼす
依頼:「金額が1200円以上の注文」。amount >= 1200 と書くと、本文のデータで注文 1、2、3、5、7、8 が出ます。一方、注文4(0円)と注文6(NULL)は出ません。
-- db: none
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
order_date TEXT NOT NULL,
status TEXT NOT NULL CHECK(status IN ('paid','cancelled','refunded')),
channel TEXT NOT NULL,
amount INTEGER,
coupon_code TEXT
);
INSERT INTO orders VALUES
(1,101,'2025-03-31','paid','web',3000,NULL),
(2,102,'2025-04-01','paid','app',1200,'SPRING'),
(3,101,'2025-04-01','cancelled','web',2500,NULL),
(4,103,'2025-04-10','paid','store',0,NULL),
(5,104,'2025-04-15','refunded','app',1800,'SPRING'),
(6,102,'2025-04-20','paid','web',NULL,NULL),
(7,105,'2025-04-30','paid','web',1200,''),
(8,103,'2025-05-01','paid','app',4000,'VIP');
SELECT order_id, amount FROM orders WHERE amount >= 1200 ORDER BY order_id;
-- 「金額が1200円未満」を求めたつもりで書く
SELECT order_id, amount FROM orders WHERE amount < 1200 ORDER BY order_id;
2つ目の結果は注文4(0円)だけです。注文6(金額NULL)が出ません。「1200以上」と「1200未満」を足しても、全8件にならず、注文6が漏れます。NULLは大小の比較で真にも偽にもならないためです。直し方:条件が漏れなく排反(重ならず、足すと全部)になっているか、件数 6+1+1=8 で確認する。NULLを含む列には IS NULL の条件を明示する(NULLと3値論理)。
まとめ
- WHERE は行にふるいをかける。真になった行だけが残り、列は減らない。
- AND は OR より先に評価される。混ぜるときは必ず括弧で意図を明示する。
- 期間は「>= 開始日 AND < 翌期間の開始日」の半開区間で書く。BETWEEN は両端を含む。
- NULLは大小の比較に入らない。「以上」と「未満」の件数を足して元の件数と合うか確かめる。
- 条件を書いたら、小さなデータの目視と件数で検算する。
用語
- WHERE(WHERE)
結果に残す行を選ぶ条件。条件が真になった行だけが残る。
- 半開区間(half-open interval)
開始を含み終了を含まない範囲。日付なら「開始日以上、翌期間の開始日未満」。
- 論理演算子(logical operator)
AND(かつ)、OR(または)、NOT(否定)。ANDはORより先に評価される。
- 比較演算子(comparison operator)
=、<>、<、>、<=、>= など、2つの値を比べて真偽を返す記号。
よくある質問
WHERE と HAVING の違いは?
WHERE は集計の前に行を絞り、HAVING は集計の後に集計結果(件数・合計)を絞ります。この授業では集計を使わないので WHERE だけです。HAVING は 「HAVINGとWHERE」(有料版) で扱います。
= と == のどちらを使いますか?
SQLでは比較に = を1つだけ使います。代入の意味はなく、「等しいか」の判定です。== もSQLiteでは使えますが、ほとんどのデータベースでは使えないので、= に統一するのが安全です。
文字列の引用符は一重と二重のどちらですか?
文字列の値は一重引用符 'paid' です。二重引用符は列名や表名を囲む用途です。SQLiteは二重引用符を文字列として解釈することがありますが、他のデータベースではエラーになるため、値は一重引用符にします。
期間の条件を `<= 月末日` ではなく `< 翌月1日` で書くのはなぜですか?
月末日が28日・30日・31日と一定でなく、データが時刻付きになると月末日の注文が漏れるからです。翌月1日の0時より前、と考えれば、月の長さや時刻形式に関係なく正しく動きます。
仕事で、条件が正しいかどうかをどう確かめますか?
(1) 小さな表で目視と一致するか、(2) 条件を足すごとに件数が減る方向に動くか、(3) 排反な条件の件数の合計が元の件数と一致するか、を確かめます。KPIの定義書に書かれた件数と照合するのも有効です。
LIKE と = の使い分けは?
完全一致なら =、先頭や一部の一致なら LIKE です。商品名の前方一致などで使いますが、表記ゆれ(全角・半角)を吸収するものではありません。値が確定しているコード類は = や IN を使うのが確実です。
確認問題
問1 WHERE status = 'paid' AND channel = 'web' OR channel = 'app' は、どのように評価されるか。
- ① 構文エラーになる
- ② status = 'paid' AND (channel = 'web' OR channel = 'app')
- ③ (status = 'paid' AND channel = 'web') OR channel = 'app'
- ④ OR が先に評価され、AND は無視される
解答と解説
正解:③
AND は OR より先に評価されます。そのため、app の注文は状態に関係なく入ります。
問2 2025年4月の注文を取り出す条件として、最も安全な書き方はどれか。
- ① order_date >= '2025-04-01' AND order_date < '2025-05-01'
- ② order_date > '2025-04-01' AND order_date < '2025-04-30'
- ③ order_date LIKE '2025-04'
- ④ order_date BETWEEN '2025-04-01' AND '2025-04-30'
解答と解説
正解:①
半開区間なら、時刻付きのデータでも月末の取りこぼしが起きません。
問3 BETWEEN 10 AND 20 はどの範囲を表すか。
- ① 10より大きく20以下
- ② 10より大きく20より小さい
- ③ 10以上20未満
- ④ 10以上20以下
解答と解説
正解:④
BETWEEN は両端を含みます。
問4 amount >= 1200 と amount < 1200 で取り出した2つの結果を足しても、表の全行にならない。考えられる理由はどれか。
- ① AND を使っていない
- ② amount が NULL の行がある
- ③ WHERE が二重に評価された
- ④ SELECT が列を減らした
解答と解説
正解:②
NULLは大小の比較で真にならないため、どちらの条件にも入りません。
問5 status IN ('cancelled', 'refunded') と同じ結果になる条件はどれか。
- ① status <> 'paid' AND status <> 'cancelled'
- ② status LIKE 'c%'
- ③ status = 'cancelled' AND status = 'refunded'
- ④ status = 'cancelled' OR status = 'refunded'
解答と解説
正解:④
IN はリストのどれかと等しい、という OR の短い書き方です。
問6 本文の注文表で、4月(2025-04-01以上2025-05-01未満)かつ paid の注文は何件か。
- ① 4件
- ② 5件
- ③ 6件
- ④ 3件
解答と解説
正解:①
注文2、4、6、7の4件です。3は取消、5は返金で除かれます。
次に学ぶこと
次は ORDER BYとLIMIT で、結果の並べ替え(ORDER BY)と上位N件の取得(LIMIT)を学びます。NULL の比較と3値論理は NULLと3値論理、日付や型は 型・日付・式 です。
この授業の確認問題だけで習得とはしません。モジュール テーブル・SELECT・条件抽出 の総合テストと自力課題で判定します。
キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。
アプリを無料で開く有料版と無料版の違い