NULL設計

NULL は「無い」ではない

NOT NULL を付けるかどうかは、型を決めるのと同じくらい重要な設計判断です。ところが、なんとなく全部 NULL 許可にしたまま運用が始まる現場は少なくありません。

まず、NULL が何を意味するのかをはっきりさせます。NULL は値が無いという印であって、0 でも空文字でもありません。

意味
0数えたら0だった
''文字が0文字だった
NULLまだ分からない、または該当しない

在庫数が 0 なら「在庫を数えて0個だった」、NULL なら「まだ数えていない」です。この2つを混ぜると、集計が意味を失います。

NULL は計算に伝染する

NULL の扱いにくさは、計算に混ざると結果まで NULL になることです。

SELECT 100 + NULL; -- NULL SELECT NULL = NULL; -- NULL (true ではない)

2行目が特に厄介です。NULL 同士は等しくありません。 「分からない値」と「分からない値」が同じかどうかは、分からないからです。

そのため WHERE column = NULL は永遠に何も返しません。NULL を探すには IS NULL を使います。この落とし穴は、NULL を許した列がある限りずっと付いて回ります。

判断の基準

列ごとに、次の質問を1つだけします。

この列の値が、行を作る時点で必ず決まっているか。

必ず決まっているなら NOT NULL です。店舗名は、店舗を登録する時点で決まっています。

あとから決まるなら NULL を許します。出荷日は、配送の行を作る時点ではまだ決まっていません。

そもそも該当しない場合があるなら NULL を許します。追跡番号は、店頭受け取りの配送には存在しません。

迷ったら NOT NULL から始める

設計の初期は、まず全部に NOT NULL を付けて、外す理由が説明できた列だけ外す、という進め方が安全です。

理由は非対称だからです。あとから NOT NULL を外すのは一瞬で終わります。逆に、NULL が入ってしまった列にあとから NOT NULL を付けるには、既存の NULL 行をどうするかを決めなければならず、たいてい大仕事になります。

厳しく始めて緩めるのは簡単、緩く始めて締めるのは難しい。 制約全般に言えることです。

空文字で代用しない

もう1つよくある逃げが、NULL を避けるために空文字を入れることです。これは NULL の問題を隠すだけで、解決していません。

「値が無い」ことを空文字で表すと、「本当に0文字だった」場合と区別できなくなります。表現したいものが2つあるなら、区別できる形で持つべきです。

手を動かす

配送テーブルの各列について判断し、NOT NULL を確定させます。

テーブル構造

CREATE TABLE orders ( id integer PRIMARY KEY ); CREATE TABLE shipments ( id integer PRIMARY KEY, order_id integer, carrier text, shipped_on date, tracking_no text ); INSERT INTO orders VALUES (1), (2), (3); INSERT INTO shipments VALUES (1, 1, 'ヤマト', DATE '2026-04-01', '1234-5678'), (2, 2, '佐川', NULL, NULL), (3, 3, '店頭', DATE '2026-04-02', NULL);

期待される出力

column_nameis_nullable
idNO
order_idNO
carrierNO
shipped_onYES
tracking_noYES

ヒント

query.sql
学習モード
コードの実行結果
データベースを初期化中...