三値論理とUNKNOWN
NULL = NULLがTRUEにならない理由と、条件の中でUNKNOWNが伝播する仕組みを学びます。
「三値論理とUNKNOWN」はCoddyKit上の無料SQL Interview Prepレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSQL Interview Prep学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 SQL Interview Prepコースには全4レッスンが含まれています。
NULLが候補者を悩ませる理由
NULLは、SQLの面接で間違った回答を生む最大の要因です。落とし穴は、NULLを通常の値として扱ってしまうことです。実際には、NULLは「不明」または「欠落」を意味し、ゼロでも空文字列でもありません。
面接官がこの問題を好むのは、構文は正しそうに見えるのに、結果がひそかに間違うからです。「行を返すはずの」フィルターを示して、なぜ何も返さないのかを尋ねることがあります。
このレッスンでは、NULLに関するあらゆる質問に対応できる考え方、つまり3値論理を身につけます。比較結果がTRUE、FALSE、UNKNOWNのいずれかになることを理解すれば、後は自然に説明できます。
NULLは値ではない
面接で口にすべき最も重要な一文は、NULLは値そのものではなく、値が存在しないことを表すということです。
そのため、数値を比較するように = で比較することはできません。データベースには、2つの不明な値が等しいかどうかを判断できないため、TRUEともFALSEとも断定しません。
NULL = 5はFALSEではなくUNKNOWNですNULL = NULLはTRUEではなくUNKNOWNですNULL <> NULLもUNKNOWNです
このため、NULLを許容する列に単純な等価比較のフィルターを使うと、行がひそかに除外されます。
2値論理と3値論理
多くのプログラミング言語では2値論理を使います。式の結果はTRUEまたはFALSEのどちらかです。SQLでは、NULLが比較に関わると3つ目の結果であるUNKNOWNが加わります。
つまりSQLの述語は、TRUE、FALSE、UNKNOWNの3つの結果のいずれかになります。WHERE句は、述語が厳密にTRUEになった場合にだけ行を残します。フィルタリングではUNKNOWNはFALSEと同じように扱われますが、論理的には同じものではありません。
面接官がこの違いを確認するのは、UNKNOWNがFALSEとは異なり、NOT の下で別の振る舞いをするからです。
行をひそかに除外するフィルター
典型的な例を見てみましょう。bonus がNULLになることがあるとします。採用担当者が次のように尋ねます。「このクエリはボーナスが1000ではない全員を返すはずです。なぜボーナスがない従業員を除外するのでしょうか」
bonus がNULLの行では、bonus <> 1000 の結果はTRUEではなくUNKNOWNです。WHEREはTRUEの行だけを残すため、その従業員は結果から消えます。
NULLを明示的に扱うことが解決策ですが、その方法は次のレッスンで説明します。ここでは、欠落した行がバグではなく、論理の結果であることを理解してください。
SELECT name, bonus
FROM employees
WHERE bonus <> 1000;
-- Rows where bonus IS NULL are excluded:
-- NULL <> 1000 evaluates to UNKNOWN, not TRUEAND式におけるNULL
3値論理では、AND の振る舞いが変わります。このルールを覚えておけば、面接でどのような真理値表の質問をされても、その場で答えられます。
- TRUE AND UNKNOWN = UNKNOWN
- FALSE AND UNKNOWN = FALSE
- UNKNOWN AND UNKNOWN = UNKNOWN
直感的には、AND は1つでもFALSEがあれば、結果を確実にFALSEにできます。そのため、FALSE AND 何であってもFALSEのままです。一方、TRUE AND UNKNOWNは依然としてUNKNOWNです。不明な側がどちらの結果になる可能性もあるためです。
-- If status = 'active' is TRUE but bonus = 100 is UNKNOWN:
SELECT *
FROM employees
WHERE status = 'active' AND bonus = 100;
-- Combined result is UNKNOWN, so the row is NOT returnedOR式におけるNULL
OR は AND と対照的な振る舞いをします。1つでもTRUEがあれば結果を確実にTRUEにできるため、TRUEによってUNKNOWNの影響がなくなります。
- TRUE OR UNKNOWN = TRUE
- FALSE OR UNKNOWN = UNKNOWN
- UNKNOWN OR UNKNOWN = UNKNOWN
つまり、OR条件の一方の分岐がUNKNOWNでも、もう一方の分岐が明確にTRUEであれば、その行は条件に一致します。これは、ANDに関する質問の後によく出される追加質問です。
SELECT *
FROM employees
WHERE department = 'Sales' OR bonus = 100;
-- A Sales employee with NULL bonus:
-- TRUE OR UNKNOWN = TRUE, so the row IS returnedNOTはTRUEとFALSEを反転するがUNKNOWNは変えない
最後に面接官が出す、微妙なポイントです。NOT はTRUEをFALSEに、FALSEをTRUEに反転しますが、NOT UNKNOWNはUNKNOWNのままです。
そのため、失敗した条件を単に NOT で囲んでも、結果を反転させることはできません。NULLの行で bonus = 1000 がUNKNOWNなら、NOT (bonus = 1000) もUNKNOWNなので、その行はやはり除外されます。
否定によってNULLの行を救うことはできません。救えるのは、明示的な IS NULL テストだけです。
-- For a row where bonus IS NULL:
-- bonus = 1000 -> UNKNOWN
-- NOT (bonus = 1000) -> UNKNOWN (still excluded)
SELECT * FROM employees WHERE NOT (bonus = 1000);実例:NOT INの落とし穴
これは、NULLに関する質問で最もよく出されるものの1つです。NULLを含むリストに対して NOT IN を使うと、NULLを単に無視すると思っている候補者を驚かせることに、行がまったく返されません。
内部的には、x NOT IN (1, 2, NULL) は x <> 1 AND x <> 2 AND x <> NULL に展開されます。最後の比較がUNKNOWNになり、TRUE AND TRUE AND UNKNOWNの結果はUNKNOWNになるため、条件を満たす行はなくなります。
安全な代替手段は NOT EXISTS です。これはこの問題の影響を受けません。
-- Returns ZERO rows if the subquery yields any NULL
SELECT name
FROM employees
WHERE manager_id NOT IN (SELECT manager_id FROM managers);
-- Each comparison against NULL becomes UNKNOWN,
-- and the AND-chain collapses to UNKNOWN for every row.WHEREでUNKNOWNがFALSEのように振る舞う理由
よくある追加質問は次のとおりです。「UNKNOWNはFALSEではないのに、なぜFALSEの行と同じように除外されるのですか」
正確な答えは、WHERE、ON、HAVINGがすべてTRUEだけを残すルールを使うからです。FALSEとUNKNOWNはどちらもこの判定に失敗するため、フィルタリングでは同じように見えます。
違いが現れるのは、否定とCHECK制約の場合だけです。CHECK制約は条件がTRUEまたはUNKNOWNのときに行を通すため、ブロックできると思っていたCHECKをNULLがすり抜けることがあります。
-- CHECK passes on TRUE or UNKNOWN, so NULL salary is allowed:
-- CONSTRAINT salary_positive CHECK (salary > 0)
-- INSERT ... salary = NULL -> NULL > 0 is UNKNOWN -> allowedより深い例:COUNTと真偽値のギャップ
現実的な面接問題で、ここまでの内容を結び付けてみましょう。「従業員が100人います。SELECT COUNT(*) WHERE bonus = 100 は30を返し、WHERE bonus <> 100 は50を返します。残りの20人はどこにいるのでしょうか」
残りの20人のボーナスはNULLです。= 100 も <> 100 も、その従業員に対してTRUEにはならず、どちらもUNKNOWNになるため、両方のフィルターを通り抜けてしまいます。
「NULLはどちらの述語も満たさないため、分類した件数の合計が全体の件数と一致しません」と答えれば、面接官がまさに求めている回答になります。
SELECT
COUNT(*) FILTER (WHERE bonus = 100) AS eq_100,
COUNT(*) FILTER (WHERE bonus <> 100) AS ne_100,
COUNT(*) FILTER (WHERE bonus IS NULL) AS null_bonus,
COUNT(*) AS total
FROM employees;面接で押さえるポイント
NULLの論理が話題になったら、シニアらしさを示すために次の点を押さえてください。
- NULLは不明を意味し、NULLとの比較結果はUNKNOWNになります。
- SQLは3値論理、つまりTRUE、FALSE、UNKNOWNを使います。
- WHERE、ON、HAVINGはTRUEの行だけを残します。
NOT UNKNOWNもUNKNOWNのままなので、否定してもNULLの行は復元されません。- NULLを1つでも含む
NOT INは行を返しません。代わりにNOT EXISTSを使います。
まずモデルを説明し、その後で真理値表を順に説明してください。そうすれば、単なる暗記ではなく、理由まで理解していることが伝わります。
確認問題
3値論理をどの程度理解できているか確認しましょう。
まとめ
これで、NULLについての基本的な考え方を身につけました。
- NULLは不明であり、値ではありません。
=や<>で比較してはいけません。 - SQLは3値論理を使い、述語はTRUE、FALSE、UNKNOWNのいずれかを返します。
- フィルタリング句はTRUEだけを残します。UNKNOWNの行はFALSEの行と同じように消えます。
NOTはTRUEとFALSEを反転しますが、UNKNOWNは変えません。NOT INとNULLの組み合わせは0行を返します。その場合はNOT EXISTSを使います。
次は、IS NULL、IS NOT NULL、NULL安全な等価演算子を使って、NULLを正しく検査する方法を学びます。
よくある質問
「三値論理とUNKNOWN」レッスンは無料ですか?
はい。「三値論理とUNKNOWN」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、SQL Interview Prepコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 SQL Interview Prepコースには全4レッスンが含まれています。
「三値論理とUNKNOWN」で何を学びますか?
NULL = NULLがTRUEにならない理由と、条件の中でUNKNOWNが伝播する仕組みを学びます。 ブラウザで直接実行するハンズオンコードでSQL Interview Prepを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
SQL Interview Prepを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSQL Interview Prepは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「三値論理とUNKNOWN」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSQL Interview Prepレッスンでコードを書いて実行できますか?
はい。すべてのSQL Interview Prepレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。