SQLの NULL は、初心者がかなりつまずきやすい概念です。空文字や0のように見えることがありますが、意味はまったく違います。
一言でいうと
NULLは「値がない、または不明」を表す特別な状態であり、0や空文字とは別物です。
NULLと似て見える値
まず、混同しやすい値を分けます。
| 値 | 意味 |
|---|---|
NULL | 値がない、不明 |
'' | 空の文字列 |
0 | 数値のゼロ |
false | 真偽値の偽 |
たとえば、プロフィールの自己紹介文を考えます。
| 状態 | 値の例 | 意味 |
|---|---|---|
| 未入力 | NULL | まだ登録されていない |
| 空欄で登録 | '' | 空文字として登録された |
| 文字あり | 'よろしくお願いします' | 内容がある |
NULL は「空の文字列が入っている」ではなく、「値が存在しない」と考えます。
NULLの判定
NULL は = では比較しません。
SELECT *
FROM users
WHERE nickname = NULL;
この書き方は期待通りに動きません。NULL を調べるには IS NULL を使います。
SELECT *
FROM users
WHERE nickname IS NULL;
逆に、NULL ではない行を調べるには IS NOT NULL を使います。
SELECT *
FROM users
WHERE nickname IS NOT NULL;
NULLを条件で扱うときは、= NULL ではなく IS NULL を使います。
三値論理とは
SQLの条件判定は、単純な true / false だけではありません。NULL が絡むと unknown という状態が入ります。
| 比較 | 結果 |
|---|---|
1 = 1 | true |
1 = 2 | false |
NULL = 1 | unknown |
NULL = NULL | unknown |
この unknown は、WHERE では結果に残りません。WHERE は true の行だけを返すためです。
NULLを含む条件の注意
たとえば、退会していないユーザーを取りたいとします。
SELECT *
FROM users
WHERE deleted_at = NULL;
これは間違いです。正しくは次のように書きます。
SELECT *
FROM users
WHERE deleted_at IS NULL;
deleted_at が NULL なら、退会日時が入っていない、つまり退会していないと判断できます。
COALESCE
COALESCE は、NULL の代わりに別の値を使いたいときに便利です。
SELECT
name,
COALESCE(nickname, '未設定') AS display_nickname
FROM users;
nickname が NULL の場合は '未設定' と表示します。
ただし、COALESCE は表示や計算をしやすくする道具です。データ設計として NULL を許可するべきかどうかは別に考えます。
よくある誤解
| 誤解 | 実際 |
|---|---|
NULL は空文字と同じ | 空文字は値あり、NULLは値なしです |
NULL = NULL はtrue | SQLではunknownになります |
WHERE col != 'x' でNULLも取れる | NULLは比較結果がunknownになり残りません |
| とりあえず全部NULL許可でよい | 必須項目には NOT NULL を付けるべきです |
実務での考え方
NULL を許可するかどうかは、データの意味で決めます。
| 項目 | NULLを許可するか |
|---|---|
| ユーザーID | 許可しない |
| メールアドレス | サービス次第だが多くは許可しない |
| ニックネーム | 許可してもよい場合がある |
| 退会日時 | 未退会を表すためにNULLを使うことがある |
必ず存在する値にはNOT NULLを付け、存在しない状態に意味がある場合だけNULLを許可します。
まとめ
NULL は、値がない、または不明であることを表す特別な状態です。0、空文字、falseとは別物です。条件で判定するときは IS NULL / IS NOT NULL を使い、比較演算子で扱わないようにします。
参考リソース
- PostgreSQL Comparison Functions and Operators
- PostgreSQL DDL Constraints
- MySQL Working with NULL Values