日常用語でnullを理解する(2)
SQLにおけるnullは「値があることは分かっているが、それが何なのかはわからない」という意味だ。
「値がない」という意味ではない、ということに注意しなくてはならない。
nullは「値がない」ではない
nullを「値がない」という意味だと考えてしまうと、
- 'a'と'b'とnullを連結した結果が、nullになる
- 1 + nullがnullになる
といったSQLの挙動の意味が理解できなくなる。
nullが「値がない」という意味なら
select 'a' || 'b' || null
の結果には少なくとも'ab'が含まれているはずあって、「値なし」になってしまうのはおかしい。
また
select 1 + null
の結果が「値なし」になってしまうのも何だかよくわからない。
つまりSQLは、nullを「値がない」という意味のものとしては扱わない。
が、「値がない(まだない or あり得ない)」という意味でnullを使う、ということは普通に行われているように見える。
ここに「nullは不可解な、恐ろしいものだ」と言われるようになった原因の一つがあると思う。
nullは「値はあるが、何かはわからない」という意味
ここで
select 'a' || 'b' || null
のnullは、「xかもしれないし、yyかもしれないし、zzzかもしれない。... 何だか分からない」という意味だ、と考え直してみる。
すると、'a', 'b', nullの連結結果は「abxかもしれないし、abyyかもしれない。... 何だか分からない」ということになる。
よって、結果もまたnull(=値はあるが、わからない)でよい、と理解できる。
同様に
select 1 + null
も、1に何だか分からない値を足したら、その結果もまた何だか分からない。なのでnullでよい、と理解できる。
nullは不可解じゃない
以下のSQLは、サブクエリが { 22, 23, null } という、nullを含む集合を返すために、結果が常に0件になる。
- Bクラスの東京在住の生徒と年齢が一致しないAクラスの生徒を選択するSQL?
SELECT *
FROM Class_A
WHERE age NOT IN ( SELECT age
FROM Class_B
WHERE city = '東京' );
この挙動をどう解釈すればよいか。
Class_Aの生徒の年齢は 19, 21, 22 のいずれかである。
また、サブクエリが返すnullは「値がわからない。それは19かもしれない。21かもしれない。22かもしれない」という意味なので、Class_Aの生徒の年齢は、いずれもその「わからないもの」に一致する可能性がある*1。
よって「Bクラスの東京在住の生徒と年齢が一致しない」ことを保障できるAクラスの生徒は存在しない。だから結果は0件になる。
人間である以上、実世界の生徒に年齢はかならずあるのだから、この結果は理にかなっている。
nullが不可解になるケース
上でも書いたけどnullを「値がない」という意味で使う、ということは普通に行われている。
例えば顧客マスタに法人客と個人客を両方放り込んで、個人にあって法人にない属性=例えば生年月日とかは、法人客のレコードではnullにしておくとか。
あるいは顧客マスタの住所1・住所2には市町村と番地を、住所3には建物と号室を入力する、というときに、一戸建てに住んでいる顧客は住所3をnullにするとか。
SQLはnullを「値がわからない」の意味で扱うので、「値がない」のnullをSQLに渡すと、その結果は意味不明になってしまう。
その話を次回書いて終わりにする予定。
*1:両者を比較した結果は「trueかもしれないし、falseかもしれない」=unknown