ホームリレーショナル・データベースの世界

  •  著者は DBMS のユーザに対し、ベンダがサポートしている 3VL を完全に無視し、そのかわりに統制された「デフォルト値」スキーマ(2値論理にしっかりと根ざしている)を利用することを薦める。……言い換えれば NULL と 3VL は関係モデルの全体的な基盤を害しているのである。
    C.J.デイト[1]

 3値論理(three-valued-logic, 3VL)は、NULL が関係モデルにもたらす問題の中でも、最も込み入った、混乱しがちなものであり、同時に最も面白い問題でもあります。私は個人的に、3値論理という体系に興味を持っています。しかし、誤解しないでいただきたいのですが、DB設計の段階においては、全力をもって NULL を追い出してください。可能な限りの列に NOT NULL制約をつけてください。そうすれば、エレガントな2値論理の世界の住人となる権利を得ます。反対に、重要なキー列に NULL を許すような設計を行なえば、混乱と未知の支配する3値論理の世界へ渡らねばなりません。ダンテが通った地獄の門には「この門をくぐる者、すべての希望を捨てよ」と書いてあったそうですが、3値論理の世界の門には差し詰めこう書いてあるでしょう。「この門をくぐる者、場合により命題の真偽を捨てよ」。

 このコラムでは、3値論理についての基礎的な知識の整理と、それがもたらす厄介な問題群の紹介を行ないます。これらの災厄に対抗するための設計方針やSQLの書き方など実践的な話は、「NULL撲滅委員会」にまわすので興味ある方はこちらも参照ください。ただ、念のためもう一度繰り返します。テーブル設計のときは可能な限り NOT NULL制約をつけてください。

二つのNULL、3値論理か、それとも4値論理か



 3値論理の話を始めるに当たり、まず NULL についての話をしようと思います。なぜかというと、NULL こそが3値論理の元凶だからです。3値論理は、私たちにとって決して馴染み深い体系ではありません。高校までに習う数学では2値論理が採用されていますし、関係モデルの基礎理論の一つである述語論理も2値論理を原則とし、計算機もブール代数という2値論理に基づいて動作します。それなら、なぜリレーショナル・データベースの世界でのみ、3値論理という奇妙な体系が幅を利かせているのでしょう?

 それはひとえに NULL のせいです。

この奇妙なトークンの存在を許したことで、関係モデルは true でも false でもない、unknown という第三の真理値を、つまりは3値論理を導入せざるを得なくなりました。それどころか驚かないでください。関係モデルの創始者コッドは、NULL をさらに2種類に分け、4値論理を採用することを提唱していたのです[2]

 コッドが言う二つの NULL とは何でしょう。それは「未知(UNKNOWN)」(サングラスをかけた人の眼の色)と「適用不能(Not Applicable)」(自動車の眼の色)です[3]。サングラスをかけた人の眼の色を知ることはできません。その人が何色かの眼の色を持つことは間違いありませんが、その色が何色かまでは分かりません。つまり、(1)ある個体が存在し、(2)その個体がある属性を持つことも分かっているが、具体的にどのような値であるかを知らない、という場合です。これが一つ目の NULL(未知)です。一方、「自動車の眼の色」という概念は、そもそも無意味です。「丸い正方形」や「長方形の体積」という概念と同じように。自動車に眼はないのだから、その色を問うことはできません。つまり、この場合は、(1)ある個体が存在し、(2)しかしその個体はある属性を持っていない、ということです。これが二つ目の NULL(適用不能)です。

 コッドによる「失われた情報」の一覧表を引用しますので、参考にしてください。

  RDBMS における失われた情報の分類[4]

db_3vl_img_1.gif


 現在の全ての DBMS の実装では、この二つの区別は行わず、ひとくくりにして「NULL」という特殊記号で表現しています。これは歓迎すべきことだと、私は思います。3値論理でさえ十分難しいのに、 NULL を二つに分けて4値論理を採用した日にはどれほど複雑な DBMS が出来上がるか知れたものではありません。

 それでは簡単な練習問題です。次の表の1~4に、未知(UNK)か適用不能(N/A)を入れてみてください。解答はここです[5]

個体名 性別 重さ 虫歯の本数
山田太郎 80kg
自動車 120kg N/A
ドラえもん N/A UNK
ミック UNK



なぜ「= NULL」ではなく「IS NULL」と書かなくてはならないのか?



 これは、気になっている人も多いはずです。まだ SQL に不慣れな頃、ある列が NULL である行を選択しようとして、

  SELECT *
  FROM table_A
  WHERE col_1 = NULL;

 というクエリを書いてしまい、エラーになったり思い通りの結果が得られなかった、という経験は、ほぼ全ての人が持っているでしょう。ちょうど C言語や JAVA を習い始めのころに「if (a = 5)」と書いてしまう間違いとよく似ています。最初は、言語仕様の汚さにぶつぶつ文句をいいながらも、そのうち「IS NULL」という書き方に慣れてしまって、疑問を持たなくなります。

 でもどう考えても奇妙な書き方ですよね。こんな素直でない書き方をしなくてはならないということには、やはりそれなりの理由があるのです。今からその理由を説明します。特に難しいことではありません。これでもう、「IS NULL」の違和感に悩まされることはありません。

 理由は、NULL に「=」を適用した結果が必ず unknown になるからです[6]。一方、「=」という比較述語を使って WHERE句を作った場合、選択対象となる行は、「a = b」の判定結果が true になる行だけです。falseunknown はダメです。そして「a = b」の結果が true になるのは、a と b がともに NULL でなく、かつ同じ値であるときに限ります。

 もし仮に a か b のどちらか一方でも NULL の場合、結果は unknown になります(もちろん a, b 両方が NULL の場合も unknown になります)。したがって、「col_1 = NULL」の結果は、col_1 の値によらず true にはならず、クエリはめでたく失敗、一行も選択できないか、DBMS によってはエラーを返すこともあるでしょう。結局、当該の列が NULL であるか否かを調べるために「=」を使うことはできず、別の述語「IS NULL」を用意する必要が生じるのです。

 では何故「col_1 = NULL」の結果が絶対に true にならないのか? その理由は、そもそも NULL が値でも変数でもないからです[7]。だから、「=」のような値と変数にしか適用できない比較述語の入力項に、NULL を用いることは不可能なのです。

 「NULL が値じゃない? そんな馬鹿な。おまえの言うことは信用ならん」という人のために、コッドとデイトの言葉を引用して権威付けしておきましょう。

  • 私たちは、まず「失われてはいるが、適用可能な値」を示すマークの定義から始めよう。これを「A-Mark」と呼ぶ。このマークは、DBMS において値(value)としても変数(variable)としても扱われない。[8]

  • NULL に関する大切なことは、厳密には NULL が値ではないということである。[9]




unknown、第三の真理値



 前章で初めて unknown という真理値が登場しました。いよいよこの3番目の真理値についてお話するときが来たわけです。最初に私が言ったことを覚えていますか? 「unknown は、関係モデルが NULL の存在を許したことで持ち込まれた"第三の値"」です。比較述語以外の述語に NULL を適用した場合にも、戻り値が unknown になる可能性があります。特に、IN述語と EXISTS述語の入力項に NULL が含まれる場合は、SQL のコーディングに大きな混乱をもたらします。この問題については次章で述べます。

 ともあれ、こうして true(真)、false(偽)、unknown(不定)の三つの真理値に基づく論理が、関係モデルに持ち込まれたのですが、ここでちょっと注意してほしいことが一つあります。それは、真理値の unknown と NULL の一種である UNKNOWN は、全く別物であるということです。前者は真理値型のれっきとした値ですが、後者は値でも変数でもありません。区別しやすいように、前者を斜体の小文字で unknown、後者を普通の大文字で UNKNOWN と表記します[10]。両者の違いを理解するには、「x = x」という単純な恒等式を例に取るのが分かりやすいでしょう。x が真理値の unknown である場合、「x = x」は true に評価されます。一方、x が NULL の UNKNOWN の場合、この式は unknown に評価されます。

 では、3値論理における論理演算の結果がどうなるか、一覧表を作って見てみましょう。太字の箇所が2値論理にはない、3値論理独特のものです。

x NOT x
true false
unk unk
false true

AND true unk false
true true unk false
unk unk unk false
false false false false
OR true unk false
true true true true
unk true unk unk
false true unk false

 SQL の他の述語は、NOT, AND, OR の三つの結合子を組み合わせることで表現できます。従って、これら論理述語の演算結果さえ定義しておけば、他の述語の演算結果も全て決定されます。ですから、上に示した三つのテーブルは、SQL の論理演算の基礎であることを肝に銘じてください。次章で、INと EXISTS の NULL に対する奇妙な振る舞いを検証します。一見、直観に反する振る舞いを見せるため、難しく感じるかもしれませんが、上のマトリックスを参照しながら読むと理解しやすいでしょう。

 では本章の理解度をチェックするための練習問題です。解答はここ[11]

   a = 3, b = 4, c = NULLとする。このとき、次の式の真理値を答えよ。
     1. a > b AND b > c
     2. a > b OR b > c
     3. a < b OR b < c
     4. NOT( a = c)

あれほど NULL を許すなと言ったのに君も話の分からない奴だな。



 NULL を許した列に IN述語や EXISTS述語を適用すると、戻り値として unknown が生じ、思っても見なかった結果に面食らうことがあります。多くのプログラマにとって、3値論理は扱いづらい体系です。その理由は、3値論理の計算が複雑なことと、学生時代に教わった数学や論理学が全て2値論理に基づいているので、2値論理の考えに慣れきってしまっていることです。

 簡単な例を出しましょう。

    SELECT * FROM SomeTable WHERE SomeColumn = 2       ・・・・・・(1)
    SELECT * FROM SomeTable WHERE SomeColumn <> 2      ・・・・・・(2)

 という二つのクエリを実行したとします。これで SomeTable の全ての行を選択できるように思えますが、そうではありません。

    SELECT * FROM SomeTable WHERE SomeColumn IS NULL   ・・・・・・(3)

 という「第3のクエリ」を実行する必要があります。(もちろん、SomeColumn に NOT NULL制約が付いていれば(3)は必要ありません)。つまり、3値論理においては、「ある列は2か、2でないかのどちらかだ」という2値論理の大原則(排中律)が通用しないのです。

 あるいは、社員の給料とボーナスの合計を求める以下のクエリは、salary 列に NULL が含まれている社員がいた場合、哀れその社員の「給料 + ボーナス」は NULL になってしまいます。

    SELECT name, salary + bonus
    FROM Employee

 理由は簡単で、NULL に「+」を適用した結果が常に NULL になってしまうからです。この予想外の結果に悩まされたくなければ、

    SELECT name, salary + bonus
    FROM Employee
    WHERE salary IS NOT NULL

として、NULLの行を除外するか、

    SELECT name, COALESCE(salary, 0) + bonus
    FROM Employee

として、加算の前に NULL を0に変換しなければなりません(くどいですが、最良の回避方法は、設計の時点であらかじめ salary列に NOT NULL制約を付けておくことです)。

 簡単な SQL でさえ、このように直観と一致しないのだから、IN や EXISTS でサブクエリを使う複雑な SQL において、NULL がどれほどの暴れっぷりを見せるか、推して知るべし、です。

NULLと NOT IN述語




 それではまず NOT IN において NULL がもたらす問題を見ましょう[12]。サンプルとして、以下のような簡単なテーブルを使います。Table2 の2行目の NULL に注目してください。
Table1
x
1
2
3
4
Table2
y
1
 
2
 では、上のテーブルに対して

    SLECT *
    FROM Table1
    WHERE x NOT IN (SELECT y FROM Table2);

 というクエリを実行した場合、結果はどうなるでしょうか。答えは空、つまり一行も返されません。「あれ?」と思った方もいるでしょう。直観に従えば、3 と 4 が返るように思われます。Table2 に NULL が含まれていなければ、結果は確かに 3 と 4 になります。ですが、NULL がこのクエリを狂わせています。以下、実行ステップを順に見てみましょう。

 1. サブクエリ「SELECT y FROM Table2」を実行
    SELECT *
    FROM Table1
    WHERE x NOT IN ( 1, NULL, 2 );

 2. NOT IN を同値変換
    SELECT *
    FROM Table1
    WHERE NOT ( x IN ( 1, NULL, 2 ));

  3. IN を OR で展開
    SELECT *
    FROM Table1
    WHERE NOT (( x = 1 ) OR ( x = NULL ) OR ( x = 2 ));

  4. ド・モルガンの法則を適用して同値変換
    SELECT *
    FROM Table1
    WHERE (( x <> 1 ) AND (x <> NULL) AND ( x <> 2 ));

  5. 「x <> NULL」は x の値によらず常にunknown に評価される
    SELECT *
    FROM Table1
    WHERE (( x <> 1 ) AND unknown AND ( x <> 2 ));

  6. 「( x <> 1 ) AND unknown AND ( x <> 2 )」は全ての x についてunknown または false になる
    SELECT *
    FROM Table1
    WHERE unknown;

 どうでしょう。段階を追うことでこの一見おかしな振る舞いの原因が NULL にあることがお分かりいただけたでしょうか。NOT IN のサブクエリで使用されるテーブルのキーに NULL が含まれている場合、結果は必ず空になるのです。

 では次の例を見てください。今度は逆に、Table1 に NULL の行がある場合です。同じクエリを投げると、今度は直観に反することなく、結果は1行で 4 が返ります。NULL の行は返されないことに注意しましょう。
Table1
x
1
2
 
4
Table2
y
1
2
3

 ではこちらの方も、クエリの実行ステップを段階的に追います。

  1. サブクエリ「SELECT y FROM Table2」を実行

  SELECT *
    FROM  Table1
    WHERE x NOT IN (1, 2, 3);


  2. NOT INを同値変換

  SELECT *
    FROM  Table1
    WHERE NOT (x IN (1, 2, 3));


  3. INをORで展開

  SELECT *
    FROM  Table1
    WHERE NOT ((x = 1) OR (x = 2) OR (x = 3));


  4. ド・モルガンの法則を適用して同値変換

  SELECT *
    FROM  Table1
    WHERE ((x <> 1) AND (x <> 2) AND (x <> 3));


  5. Table1の各行について、xに値を代入する。UNION ALLで表現する。

    SELECT *
      FROM  Table1
      WHERE ((1 <> 1) AND (1 <> 2) AND (1 <> 3))
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE ((2 <> 1) AND (2 <> 2) AND (2 <> 3))
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE ((NULL <> 1) AND (NULL <> 2) AND (NULL <> 3))
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE ((4 <> 1) AND (4 <> 2) AND (4 <> 3))


  6. 比較述語の計算を行い、真理値の定数に変換する

    SELECT *
      FROM  Table1
      WHERE (false AND true AND true)
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE (true AND false AND true)
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE (unknown AND unknown AND unknown)
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE (true AND true AND true)


  7. 真理値の計算を行い、WHERE句の条件を定数にする

    SELECT *
      FROM  Table1
      WHERE false
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE false
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE unknown
    UNION ALL
    SELECT *
      FROM  Table1
      WHERE true


  8. WHERE句がtrueとなる1行( x = 4 )のみが選択される。


NULLと NOT EXISTS述語




 次に NOT EXISTS において NULL がもたらす問題を見ます。サンプルとして、以下のテーブルを使います。トーバルズの誕生日が NULL(「未知」の NULL です!)であることに注目してください。

Personnel
name birthday
一太 02/01
二太 07/20
かのこ 12/24
Celebrities
name birthday
R.ストールマン 02/01
E.レイモンド 01/01
L.トーバルズ  


 このテーブルに対し、有名人と同じ日に生まれなかった従業員を全て選択する、次のようなクエリを発行します。さて、結果はどうなるでしょうか?

    SELECT P.name
    FROM   Personnel  P
    WHERE  NOT EXISTS (SELECT *
                      FROM   Celebrities  C
                      WHERE  P.birthday = C.birthday);

 結果:二太とかのこの二人が選択される。

 解説:一太が選択されないのは当然です。一太はストールマンと誕生日が一致するからです。では二太とかのこが選択されるのはなぜでしょう? 二人は確かにストールマンとレイモンドとは誕生日が一致しません。問題は、トーバルズの誕生日との比較です。トーバルズの誕生日は NULL です。従って、この比較は以下のようなステップを推移します。

  1. サブクエリにおいて、トーバルズの誕生日(NULL)との比較を行なう

    SELECT P.name
    FROM   Personnel  P
    WHERE  NOT EXISTS (SELECT *
                      FROM   Celebrities  C
                      WHERE  P.birthday = NULL);


  2. NULLに比較述語を適用した結果は必ず unknown になる

    SELECT P.name
    FROM   Personnel  P
    WHERE  NOT EXISTS (SELECT *
                      FROM   Celebrities  C
                      WHERE  unknown);


  3. サブクエリは結果を返さないので、反対に NOT EXSITS の評価結果は true になる

    SELECT P.name
    FROM   Personnel  P
    WHERE  true;

 誕生日が未知のトーバルズは、誰とも誕生日が一致しない人物として扱われるのです。この点に違和感を覚える人もいるでしょう。確かに現在のところ彼は誕生日を公開していないかもしれない。でもいつの日か新聞に誕生日が載るかもしれない。だから彼は全員と誕生日が一致する人物として扱われるべきではないか、と。しかし残念ながら、現在の RDBMS において、その直観は保証されません。

NOT IN述語と NOT EXISTS述語は同値ではない



 よく使われるパフォーマンス・チューニングのテクニックとして、IN を EXISTS で書き換えるというものがあります。これは全く害のない方法です。注意すべきは、NOT IN と NOT EXISTS を書き換える場合には、必ずしも互換性がないことです。「必ずしも」という条件を付けたのは、結合キーとなる列に NULL がなければ、NOT が無いときと同様、安全に書き換えられるからです。またもや、NULL が問題をもたらします。例えば、前章で例として使った NOT EXISTS を NOT IN で書き換えるとこうなります。

    --1. 有名人と同じ日に生まれなかった従業員を全て選択するクエリ
    SELECT P.name
    FROM   Personnel  P
    WHERE  NOT EXISTS (SELECT *
                      FROM   Celebrities  C
                      WHERE  P.birthday = C.birthday);

    --2. 1と同じ結果を返すクエリ???
    SELECT name
    FROM  Personnel 
    WHERE birthday NOT IN (SELECT birthday
                           FROM   Cerebrities);

 直観はここでも裏切られます。1番のクエリが二太とかのこの二人を選択することは、前章で見た通りです。一方、2番のクエリは一行も選択しません。理由はもう説明不要でしょう。

 以上で、NOT IN とNOT EXISTS でサブクエリを作る際に NULL がもたらす問題を見てきました。プログラミングの際に直観に頼ることができないというのは困難な条件ですが、DBエンジニアはこの奇妙な現象について知っておく必要があります。そして最後に、NULL の問題について最も大切なことを繰り返すなら、テーブル設計の段階で可能な限り NULL を排除すること、です。



神のいない論理



 最後に、データベースから離れて論理学について書かせてください。実務以外に興味はない、という方は強いて読む必要もないのですが、きっと面白いはずです。

 3値論理学(three-valued-logic)を史上初めて作り上げたのは、ポーランドを代表する論理学者 J.ウカシェヴィッツ (1878-1956)です[13]。1920年代、彼は「真」でも「偽」でもない第三の真理値「可能」を定義しました。

 なぜこの時期に3値論理が誕生したかというと、1920-30年代というのは、論理学において古典論理批判が始まった「革命の時代」だったからです。3値論理以外にも、ブラウワーやハイティンクらによる直観主義論理学も創始され、ここから ―― 19世紀後半までの沈滞ムードを吹き払うように ―― 絢爛たる非古典論理が華開いていきます。

 古典論理において特に批判の対象になったのが、排中律(A ∨ ¬A)という公理の一つと、それを支える2値原理でした。排中律とは「A か A でないかは常に成り立つ」ことを意味する公理で、2値原理は「ある命題は必ず真か偽に定まる」という前提です。2値原理は、私たち人間にとっては決して受け入れやすい前提ではありません。この世の中には真偽の分からない命題はそこらじゅうに転がっているではありませんか。例えば、「神は存在する」とか「殺人は悪だ」とか「6 より大きい全ての偶数は二つの奇素数の和で表せる」(ゴールドバッハの予想)とか。古典論理は、こうした疑問に対してこう答えます。「でも神様なら全ての命題の真偽を知っているはずだ。」 神様なら、どんな難しい計算も瞬時に解き、宇宙開闢以来の全歴史に精通し、お望みならタイムスリップだってできます。何しろ全知全能ですから。古典論理が「神の論理」と呼ばれる所以です。

 一方、そのような人間からかけ離れた論理学ではなく、人間の有限な認識をなるべく忠実に反映する論理学があるべきではないか、と考える人々がいます。そういう論理学においては、命題の真理値は「真」と「偽」だけではない、「無意味」とか「今のところ不明」とか「矛盾」とか、様々な認識を反映する値がありえるでしょう。こうして、3値論理が生まれ、さらに3値以上の真理値を認める多値論理学(many-valued logic)の研究がスタートしていくことになります。神のいない論理 ―― あるいは人間の論理 ―― の誕生です。

 データベースを扱う主体は、当然ながら、神様ではなく人間です。それゆえ、情報の表現方法も、神様の完全無欠な認識ではなく、有限で不完全な人間の認識を尊重しようという発想に基づいています。ここに3値論理が用いられたわけです。しかし、この人間志向的な思想は諸刃の剣でした。確かに、3値論理を(要するに NULL と unknown を)採用することで、リレーショナル・データベースは非常に人間の認識に近い、柔軟な表現力を獲得しました。しかしそれによって、皮肉にも、人間の直観に反する奇妙な論理計算をも導入しなければならなかったのです。



[1] C.J.デイト『データベースシステム概論 第6版』p.636

[2] Codd,E,F, 1990, "The Relational Model for Database Management: Version 2" p.182
 私は、コッドが4値論理を提唱していたことを知ったとき、控えめに言ってぶったまげました。そして、4値論理がどのベンダーの興味も惹かなかったことを、全てのDBエンジニアにとって喜ばしく思いました。
 参考までに、4値論理における真理値表をご覧にいれましょう。UNKNOWN の NULL のための真理値として applicalble が、Not Applicable の NULL のための真理値として inapplicable が導入されています。あくまで参考ですよ。いくら大恩あるコッド博士の言うこととはいえ、こんなもの本気で受け取ってはなりません!
x NOT x
t f
a a
i i
f t
AND t a i f
t t a i f
a a a i f
i i i i f
f f f f f
OR t a i f
t t t t t
a t a a a
i t a i f
f t a f f
 なお、これは余談の余談なのですが、4値論理は、関係モデル以外にも、知識ベースのデータベース理論においても提唱されています。知識ベースは人間の知識をデータベース化しようという発想に基づいていますが、全ての知識を知識ベースに登録することは不可能です。従って、不完全知識や矛盾知識を扱う必要があり、ここに4値論理が採用されたわけです。
 例としてベルナップの4値論理を見ましょう。彼によれば、知識ベースには次のような4つの認識状態が存在することになります。

  true :命題は真である
  false:命題は偽である
  none :命題は真でも偽でもない
  both :命題は真であり偽である

 ここで、truefalse は、古典的な2値論理から存在する真理値です。none は3値論理で言えば unknown に相当します。both が4値論理特有の、矛盾認識を表現する真理値です。

[3] Codd 1990, p.170
 コッドは、「未知」の NULL を「A-Mark」、「適用不能」の NULL を「I-Mark」と呼んでいます。A とか I というのは、「未知」の NULL は属性を適用可能(Applicable)だが、「適用不能」の NULL は属性を適用できない(Inapplicable)ことから来た呼び方です。

[4] Codd 1990, p.171

[5] 1.UNK:山田太郎は人間なので、「虫歯になる」という属性を持ちます。しかし、具体的に何本かまでは分かりません。
  2.N/A:自動車には「性別」という属性が適用できません。
  3.N/A:ドラえもんはロボットなので、「虫歯になる」という属性は適用できません。
  4.UNK:私(ミック)は人間なので当然「体重」という属性を持ちます。しかし何キロかは皆さんには分かりません。

[6] 「=」に限らず、「<」「>」「<>」など比較述語の入力項が NULL の場合、結果は常に unknown です。a の値が分からなければ、b の値にかかわらず(そしてまた b の値が分からなければなおさら) a > b であるかどうかは明らかに分かりません。

[7] 値ではないので、NULL は当然、定義域にも含まれません。NULL をデータの値であると勘違いしている人は、ここでしっかりとそういう誤った考えを捨てておきましょう(逆に聞きたいのですが、もし仮に NULL が値であるとすれば、その型は一体何なのですか?)。きわめて頻繁に使われる「NULL値」、「ナル値」、「列の値が NULL である」という言い方も、全くの間違いです。
 関係モデルにおける NULL を値と勘違いしやすい理由の一つは、おそらく、C言語や Java において NULL が一つの値(定数)として扱われている(大半の処理系では0の別名に過ぎない)ため、それと混同しがちなことでしょう。
 歴史的には、1989年、コッドが「SQL の致命的な欠点(Fatal Flaws in SQL)」という論文を発表し、関係モデルでは NULL を値として扱えないことを認めました。同様の内容を "The Relational Model for Database Management: Version 2" で読むことができます。

[8] Codd 1990, p.173

[9] デイト, p.619

[10] この表記は、デイトの『データベースシステム概論 第6版』に従いました。この表記方法が一般的なのかどうかは、私には分かりません。セルコは『プログラマのためのSQL 第2版』で真理値を大文字の TRUE、FALSE と表記していますし、あまり統一はないようです。

[11]
 1. false
 2. unknown
 3. true
 4. unknown

[12] この例は、セルコ『プログラマのためのSQL 第2版』p.184-86から借用しました。

[13] ウカシェヴィッツは、タルスキ、レスニエフスキらと一緒に「ワルシャワ学派」の中心的存在だった論理学者です(Lisp に応用されているポーランド記法を考案したのもこの人)。以下に彼の3値論理のマトリクスの例を挙げます。「可能(0.5)」という真理値があるのが特徴です。
x ¬x
0 1
0.5 0.5
1 0
x → y 0 0.5 1  
0 1 1 1  
0.5 0.5 1 1  
1 0 0.5 1  
 残りの結合子も、上の二つの結合子を使って次のように定義できます。A ∨ B = (A → B) → B、A ∧ B = ¬(¬A ∨ ¬B) です。この3値論理において、常に真理値1をとる論理式を3値トートロジー(three-valued tautology)と言います。2値論理におけるトートロジーの3値論理版です。例えば、A → A(同一律)がそうです(これは2値論理でもトートロジー)。しかし、2値論理ではトートロジーだった A ∨ ¬A(排中律)が、3値論理ではもはやトートロジーになりません。なぜなら、A が0.5のとき、¬A も0.5になり、従って A ∨ ¬A も0.5になり、1 にならないからです。
 ウカシェヴィッツの3値論理に関しては、戸田山和久『論理学をつくる』p.284 が簡明な説明を与えてくれます。

 

Copyright (C) ミック
作成日:2002/12/01
最終更新日:2017/06/22 b_entry.gif b_entry.gif