NULLの扱い方
送料を足したら、請求額が消えた
注文の表に、送料 shipping_fee がまだ入力されていない行があるとします。商品代と送料を足して請求額を出そうとすると、その行だけ結果が空になります。
SQL クエリ
SELECT id, amount + shipping_fee AS billed
FROM orders;amount が 3000 で shipping_fee が NULL の行は、billed が 3000 にも 0 にもならず NULL になります。
ここが出発点です。NULL は 0 でも空文字でもありません。「値がまだ決まっていない」という状態そのものです。分からない数に 3000 を足したら、答えもやはり分からない。だから結果は NULL になります。NULL のふるまいは全部この一点から説明が付くので、まずこれだけを持ち帰ってください。
平均だけ、母数がこっそり減る
一方で、集計関数は NULL の行を計算から外します。
SQL クエリ
SELECT
COUNT(*) AS row_count,
COUNT(shipping_fee) AS fee_count,
AVG(shipping_fee) AS avg_fee
FROM orders;100 行あって送料が入っているのが 60 行なら、COUNT(*) は 100、COUNT(shipping_fee) は 60 です。そして AVG の分母も 60 になります。全体の平均を出したつもりが、入力済みの行だけの平均だった、という取り違えがここで起きます。
足し算では答えごと消えるのに、平均では黙って除外される。逆の動きに見えますが、どちらも「分からない値は使わない」という同じ方針です。
= NULL は 1 件も返さない
未入力の行を探そうとして = NULL と書くと、エラーにならず 0 件が返ります。書き方が間違っていると教えてくれないので、いちばん気づきにくい形です。
SQL クエリ
-- 0 件が返る
SELECT id FROM orders WHERE shipping_fee = NULL;
-- 未入力の行が返る
SELECT id FROM orders WHERE shipping_fee IS NULL;= は両辺が等しいかどうかを確かめる演算子です。決まっていない値が何かと等しいかどうかは、やはり決まりません。真とも偽とも言えない答えになり、WHERE はそれを通しません。だから NULL かどうかを調べる専用の書き方として IS NULL と IS NOT NULL が用意されています。等号は使えない、と覚えてしまうのが早いです。
テーブル構造
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(30) NOT NULL,
phone VARCHAR(20),
point INT
);
INSERT INTO users (id, name, phone, point) VALUES
(1, '田中太郎', '090-1111-2222', 1500),
(2, '佐藤花子', NULL, 800),
(3, '鈴木一郎', '080-3333-4444', NULL),
(4, '高橋美咲', NULL, NULL),
(5, '伊藤健太', '070-5555-6666', 500);期待される出力
| id | name |
|---|---|
| 2 | 佐藤花子 |
| 4 | 高橋美咲 |