SQL:NULL の扱い
1学習の目的
- NULL が「0でも空文字でもない、特別な状態」であることを理解し、IS NULL で正しく判定できるようになる。
- NULL が条件・計算・集計から静かに漏れる性質を知り、集計結果が合わない原因を自力で突き止められるようになる。SQLで最も多くの人がつまずく落とし穴を回避できるようになる。
2基礎解説
NULL は「値が入っていない」という状態です。0でも空文字でもなく、「不明」を表します。
下のSQLを実行環境で流してから始めてください。SQL01〜04の問題を解き直すと件数が変わりますが、それが正しい動作です(実務でもデータは日々増えます)。
INSERT INTO products VALUES (6, '新商品A', NULL, 25000, NULL), (7, 'サンプル品', '周辺機器', NULL, 3);
| id | name | category | price | stock |
|---|---|---|---|---|
| 6 | 新商品A | NULL | 25000 | NULL |
| 7 | サンプル品 | 周辺機器 | NULL | 3 |
| やりたいこと | 正しい書き方 | 誤り |
|---|---|---|
| NULLを探す | WHERE price IS NULL | = NULL |
| NULLでないものを探す | WHERE price IS NOT NULL | <> NULL |
| NULLを別の値に置き換える | COALESCE(price, 0) | — |
| NULLでない件数を数える | COUNT(price) | — |
- = NULL は絶対に一致しない。NULLは「不明」なので、「不明 = 不明」が真になるとは限らないという考え方。エラーは出ず、静かに0件が返る。
- 判定は必ず IS NULL / IS NOT NULL。この2つだけが NULL を正しく扱える。
- NULLは通常の条件から漏れる。WHERE price > 10000 でも WHERE price <= 10000 でも、priceがNULLの行はどちらにも入らない。
- NULLを含む計算はすべてNULLになる。NULL * 3 も NULL + 100 も結果はNULL。集計が合わない原因の多くはこれ。
- COUNT(*) は全行を数えるが、COUNT(列名) はその列がNULLでない行だけを数える。この違いを知らないと件数がずれる。
現場使用例:未入力の項目を探す、退会日が未設定=現役会員の抽出、金額未確定の注文の検出、欠損データの補完。実データにNULLが無いことはまずない。
-- ❌ これは0件になる(エラーにもならない) SELECT name FROM products WHERE category = NULL; -- ✅ 正しい書き方 SELECT name FROM products WHERE category IS NULL; -- NULLでないものだけ SELECT name FROM products WHERE price IS NOT NULL; -- ⚠ NULLは条件から漏れる SELECT name FROM products WHERE price > 10000; -- → priceがNULLのサンプル品は出てこない -- NULLを別の値に置き換える SELECT name, COALESCE(category, '未分類') AS 分類 FROM products; -- COUNT の違い SELECT COUNT(*) AS 全行数, -- 7 COUNT(price) AS 価格あり; -- 6(NULLを除く) FROM products;
3基本ドリル(10問)
1行。新商品A
WHERE category IS NULL と書く。= は使えない。
SELECT name FROM products WHERE category IS NULL;
NULLの判定は IS NULL だけ。= を使うとエラーも出ずに0件が返るので、間違いに気づきにくい。
A. NULLの行が返る B. 0件になる C. 全件返る D. エラーになる 選択★☆☆無料
解答 == B
NULLは「不明」。不明どうしを = で比べると。
B
エラーにならず静かに0件が返るのが最も危険な点。「NULLのデータが1件も無い」と誤解したまま進んでしまう。
6行。サンプル品を除く全商品
WHERE price IS NOT NULL と書く。
SELECT name, price FROM products WHERE price IS NOT NULL;
データが揃っている行だけで集計したいときの定番。IS NOT NULL で欠損行を除いてから計算する。
SELECT name FROM products WHERE stock ____ NULL;
1行。新商品A
NULLの判定に使う2語。「〜である」を意味する動詞から始まる。
IS
IS は NULL 専用の比較。数値や文字列の比較には使えないので、用途が完全に分かれている。
A. 0 B. 3 C. NULL D. エラー 選択★☆☆無料
解答 == C
「不明な数」を3倍しても、答えは。
C
NULLを含む計算はすべてNULLになる。合計や平均が想定と違うとき、まずこれを疑う。
7行。新商品Aが 未分類
COALESCE(列, 代わりの値) を使う。
SELECT name, COALESCE(category, '未分類') AS cat FROM products;
COALESCE は「最初にNULLでない値」を返す関数。画面に「NULL」と表示せず、意味のある文字に置き換えるのに使う。
SELECT name, ____(price, 0) * 1.1 AS tax_price FROM products;
7行。サンプル品が 0.0
NULLを別の値に置き換える関数。8文字。
COALESCE
NULLのまま計算するとNULLになるので、先に0に置き換えてから計算する。金額の集計で欠損を0として扱いたいときの定番。
A. 同じ B. COUNT(price) はNULLを除いて数える C. COUNT(*) のほうが遅い D. COUNT(price) は合計を返す 選択★★☆無料
解答 == B
列名を指定したとき、NULLはどう扱われるか。
B
COUNT(*) は7、COUNT(price) は6になる。「入力済みの件数」を数えたいときは列名を指定する。この違いを知らないと件数がずれる。
4行。マウス / キーボード / USBメモリ / サンプル品
OR で2つの条件をつなぐ。NULLは price < 10000 に入らないので、明示的に拾う必要がある。
SELECT name, price FROM products WHERE price IS NULL OR price < 10000;
NULLは条件から漏れるので、必要なら明示的に拾う。「安い商品、または価格未定の商品」という現実的な要求はこの形になる。
6行。新商品A(categoryとstockがNULL)だけが除外される
IS NOT NULL を AND でつなぐ。
SELECT name, category, stock FROM products WHERE category IS NOT NULL AND stock IS NOT NULL;
複数の列の欠損をまとめて除く形。データ分析の前処理で「完全なデータだけを対象にする」ときによく書く。
4実践シナリオ(5問)
3列2行。新商品A / サンプル品
OR で2つの IS NULL をつなぐ。
SELECT name, category, price FROM products WHERE category IS NULL OR price IS NULL;
データの品質チェックそのもの。マスタ登録の直後にこれを流して、入力漏れを担当者に差し戻すのが実務の運用。
3列7行。新商品Aが 未分類 / 0
COALESCE を2箇所で使う。文字列には文字列、数値には数値を指定する。
SELECT name, COALESCE(category, '未分類') AS cat, COALESCE(stock, 0) AS stk FROM products;
画面に「NULL」と出さないための処理。ユーザーに見せる一覧では、欠損を意味のある表示に置き換えるのが親切。
3列1行。サンプル品 / 周辺機器 / 価格未定
SELECT に文字列をそのまま書ける。'価格未定' AS status のように。
SELECT name, category, '価格未定' AS status FROM products WHERE price IS NULL;
SELECT には固定の値も書ける。列から取るのではなく、その場で決めた文字列を全行に付けられる。区分やラベルを付けたいときに使う。
2列7行。ノートPC 640000 が先頭、新商品Aとサンプル品は 0
COALESCE を両方の列に適用してから掛ける。並べ替えは ORDER BY stock_value DESC。
SELECT name, COALESCE(price, 0) * COALESCE(stock, 0) AS stock_value FROM products ORDER BY stock_value DESC;
COALESCE を挟まないと、2件がNULLになって並べ替えの結果も変わる。「欠損は0として扱う」という業務ルールを、そのままSQLに落とし込んでいる。
① 全行数(別名 全件)② price が入力済みの件数(別名 価格あり)③ category が入力済みの件数(別名 分類あり)④ stock が入力済みの件数(別名 在庫あり) コーディング★★★無料
4列1行。7 / 6 / 6 / 6
COUNT(*) と COUNT(列名) を使い分ける。列名を指定するとNULLが除かれる。
SELECT COUNT(*) AS 全件, COUNT(price) AS 価格あり, COUNT(category) AS 分類あり, COUNT(stock) AS 在庫あり FROM products;
データの欠損状況を一目で把握するクエリ。実務でテーブルを受け取ったら、まずこれを流して「どの列がどれくらい埋まっているか」を確認する。
5仕上げ課題
表示する列
① name → 別名「商品名」
② category(NULLなら「未分類」)→ 別名「分類」
③ price(NULLなら 0)→ 別名「単価」
④ stock(NULLなら 0)→ 別名「在庫」
⑤ 在庫金額(NULLを0として扱った price × stock)→ 別名「在庫金額」
並び順:在庫金額の大きい順
絞り込み:なし(全7件を表示)
期待される結果(5列 × 7行)
商品名 | 分類 | 単価 | 在庫 | 在庫金額
ノートPC | PC | 128000 | 5 | 640000
モニター | PC | 45000 | 7 | 315000
USBメモリ | 周辺機器 | 1500 | 120 | 180000
キーボード | 周辺機器 | 8500 | 18 | 153000
マウス | 周辺機器 | 3200 | 42 | 134400
新商品A | 未分類 | 25000 | 0 | 0
サンプル品 | 周辺機器 | 0 | 3 | 0
5列 × 7行が完全一致
COALESCE を4箇所で使う(分類・単価・在庫・在庫金額の計算の中)。在庫金額は COALESCE(price,0) * COALESCE(stock,0)。並べ替えは別名で指定できる。
SELECT name AS 商品名, COALESCE(category, '未分類') AS 分類, COALESCE(price, 0) AS 単価, COALESCE(stock, 0) AS 在庫, COALESCE(price, 0) * COALESCE(stock, 0) AS 在庫金額 FROM products ORDER BY 在庫金額 DESC;
NULLを含むデータを、欠損が分かる形で扱えた。「未分類」「0」と表示されることで、データが無いことが読む人に伝わる——これがNULLをそのまま出すのとの決定的な違いだ。
そして最後の2行に注目してほしい。新商品Aは単価25000円なのに在庫金額が0、サンプル品は在庫3個なのに0。どちらか片方が欠損していれば、掛け算の結果は意味を持たない。COALESCE で0にしたことで「計算できない」ことが数字として表れている。
もし COALESCE を書かなければ、この2行の在庫金額はNULLになり、並べ替えの位置も変わる。NULLは「見えない」からこそ、意識して扱わなければ結果が静かに狂う。SQLで最も多くの人がつまずくのがこの落とし穴で、集計値が合わないときの容疑者リストの筆頭になる。
次章では集計関数を学ぶ。SUM や AVG がNULLをどう扱うか——ここでの知識がそのまま効いてくる。