記事の内容
リレーショナルデータベースのBOOLEAN型の3値論理について説明します。
説明
RDBのBOOLEAN型は、TRUE、FALSEに加えてNULLの状態にもなり得ます。
BOOLEAN型のNULLは、意味的には「TRUEかFALSEか分からない」なので、以下Unknownという値を導入します。
すなわち、RDBのBOOLEAN型はTRUE、FALSE、Unknownの3つの値を使った3値論理です。
今、customerテーブルに以下のデータが入っているとしましょう。
「三郎」の電話番号は不明なので、NULLにしてあります。
(customerテーブル)
id name tel
-------------------------------
1 '一郎' '03-1111-1111'
2 '次郎' '03-2222-2222'
3 '三郎' NULL
4 '史郎' '03-4444-4444'
customerテーブルに対して、以下の SQL文を投げてやります。
検索結果はどうなるでしょうか?
SELECT *
FROM customer
WHERE tel != '03-1111-1111'
「三郎」の電話番号は、'03-1111-1111'かもしれないし、そうでないかもしれません。
従って、WHERE句の評価結果(3値論理)は以下のようになります。
id name tel WHERE句の評価結果
----------------------------------------------------
1 '一郎' '03-1111-1111' FALSE
2 '次郎' '03-2222-2222' TRUE
3 '三郎' NULL Unknown
4 '史郎' '03-4444-4444' TRUE
結果表に含まれるのは、WHERE句の評価結果がTRUEの行のみです。
従って上記のSQL文で検索されるのは、「次郎」と「史郎」の2件です
では、以下の SQL文ではどうでしょうか。
SELECT *
FROM customer
WHERE tel != '03-1111-1111'
OR tel IS NULL
直感では「次郎」「三郎」「史郎」の3件が検索されそうです。
そして実際にそうなります。
では、このWHERE句が「三郎」の行に適用された場合について、厳密にみていきましょう。
「tel != '03-1111-1111'」の評価結果はUnknownです。
「tel IS NULL」の評価結果はTRUEです。
従って、三郎のデータでのWHERE句は「Unknown OR TRUE」となります。
ここから最終結果を得るのはやっかいですが、「UnknownをTRUEとFALSEで置き換える」という技があります。
その結果が両方TRUEであればTRUE、両方FALSEであればFALSE、それ以外はUnknownです。
実際に置き換えてみると、「TRUE OR TRUE」も「FALSE OR TRUE」もTRUEですから、両方TRUEということで最終結果はTRUEになり、「三郎」も検索されるということになります。
TRUE AND Unknown → Unknown(TRUE AND TRUE → TRUE、TRUE AND FALSE → FALSE)
FALSE AND Unknown → FALSE (FALSE AND TRUE → FALSE、FALSE AND FALSE → FALSE。両方FALSE)
Unknown AND Unknown → Unknown
TRUE OR Unknown → TRUE (TRUE OR TRUE → TRUE、TRUE OR FALSE → TRUE。両方TRUE)
FALSE OR Unknown → Unknown(FALSE OR TRUE → TRUE、FALSE OR FALSE → FALSE)
Unknown OR Unknown → Unknown
NOT Unknown → Unknown(NOT TRUE → FALSE、NOT FALSE → TRUE)
これらのことから得られる教訓があります。
それは、スキーマ定義の時「列はデフォルトでNOT NULL制約を付けよ」ということです。
NULLが絡むとSQL文が複雑になり、面倒です。
NULLを可にする理由がなければ、NOT NULL制約を付けるべきです。