NULL を扱う - NULL の扱い
3 値論理、IS NULL / IS NOT NULL、COALESCE / NULLIF / NVL、NULL による集約や比較のハマりどころ
概念図
構文
sql
col IS NULL / col IS NOT NULL / COALESCE(a, b, ...) / NULLIF(a, b)サンプル
COALESCE でフォールバック、NULLIF で空文字を NULL に正規化、IS NULL で論理削除除外
sql
SELECT id,
COALESCE(nickname, name, 'Anonymous') AS display_name,
NULLIF(phone, '') AS phone_clean
FROM users
WHERE deleted_at IS NULL;NULL と 3 値論理
SQL の真偽値は TRUE / FALSE / UNKNOWN の 3 つあります。NULL との比較(col = 1 など)はすべて UNKNOWN になり、WHERE では除外されます。
NULL = NULL→ UNKNOWN(TRUE ではない)NULL <> 1→ UNKNOWN(FALSE ではない)NULL AND TRUE→ UNKNOWN、NULL OR TRUE→ TRUE
IS NULL / IS NOT NULL
NULL かどうかを判定するには 必ず IS NULL / IS NOT NULL を使います。= NULL / <> NULL は常に UNKNOWN を返すため、意図した結果になりません。
sql
-- 間違い: 何もヒットしない
SELECT * FROM users WHERE deleted_at = NULL;
-- 正しい
SELECT * FROM users WHERE deleted_at IS NULL;COALESCE / NULLIF / NVL
COALESCE(a, b, c, ...): 左から見て最初に NULL でない値を返す。標準 SQL、全 RDBMS で利用可NULLIF(a, b):a = bなら NULL、そうでなければa。ゼロ除算の回避(NULLIF(divisor, 0))や空文字の正規化に便利NVL(a, b)は Oracle 方言(2 引数版の COALESCE)。IFNULL(a, b)は MySQL / SQLite、ISNULL(a, b)は SQL Server。移植性が必要ならCOALESCEを使う。RDBMS 間の差分は RDBMS 方言早見表 にまとめています
sql
-- ゼロ除算を NULL にする
SELECT amount / NULLIF(quantity, 0) AS unit_price FROM items;集約関数と NULL
集約関数は基本的に NULL を無視します。
COUNT(*): NULL も含めて行数を数えるCOUNT(col):colが NULL でない行だけ数えるSUM/AVG/MAX/MIN: NULL は除外して計算(全行 NULL だと結果も NULL)AVGは NULL を 分母にも入れないので、ゼロ扱いにしたいならCOALESCE(col, 0)でラップする
落とし穴: NOT IN と NULL
サブクエリの結果に NULL が混ざっていると NOT IN は 一行も返さなくなることがあります。x NOT IN (1, 2, NULL) は x <> 1 AND x <> 2 AND x <> NULL と展開され、最後が UNKNOWN なので全体も UNKNOWN になるためです。
安全のため、NULL を含み得る列には NOT EXISTS を使うか、サブクエリ側で WHERE col IS NOT NULL を明示してください。
