はじめに
真理値と論理演算の重要性
プログラマやSEのみなさんは、真理値(真偽値)というものをご存じのことと思います。ほとんどの言語が持っている基本的なデータ型で、数学者George Booleの名前にちなんで「BOOL型」とか「BOOLEAN型」とも呼ばれています。コンピュータを利用していると、BOOLEAN型が持つtrue(真)とfalse(偽)の2つの値と、NOT、AND、ORという3つの演算子だけから成るシンプルな演算(論理演算)を行うことが多くあります。これはプログラミング言語だけでなく、コンピュータの回路の基礎にもなっている演算です。
SQLにおける真理値と論理演算
SQLにも、真理値と論理演算が存在します。存在するどころか、WHERE句やHAVING句は、それ全体が論理演算のカタマリです。だから真理値はSQLの根幹をなす重要な要素と言っていいのですが、それにもかかわらず、SQLとリレーショナルデータベースは極力、この真理値と論理演算をユーザから隠そうとする傾向があります。標準SQLに正式のデータ型として真理値が追加されたのは、SQL-99でした。SQLの誕生[1]から25年も後のことです。しかも、真理値型をサポートしているDBMSもまだ多くありません(後述)。
では、なぜSQLとRDBは真理値の存在を隠そうとするのでしょう?理由は、そこに後ろ暗いところがあるからです。真理値は、ときにSQLの「致命的な欠陥」とまで呼ばれるほどの大きな問題を抱えた領域です。
本稿を読んで初めてこの話題について知ることになる人は、かなり混乱した印象を受けるかもしれません。
それは一部には、筆者の力不足によるものです。しかし、より本質的には、そもそも始まりからして混乱しているからなのです。SQLも、そしてデータベースの各実装も、この問題に対する態度は混乱をきわめていて、しかもいっこうに収拾の気配を見せません。
それでも、SQLにとって真理値と論理演算が重要な技術要素であることに変わりはありません。本稿の最後で、SQLを論理演算の観点から使いこなすといかに便利かを解説します。
- 読者対象
- 真理値と言えばtrueとfalseしかないと思っている人
- 「3値論理」は知っていたけど、第3の値をNULLだと思っている人
- SQLで真理値と論理演算の存在を意識したことのない人
- 稼働環境
.
各DBの真理値型のサポート
DBによりサポート状況/扱い方が異なる
真理値型の列を持つテーブルを作るのはとても簡単で、次のようにデータ型をBOOLEAN型で宣言するだけです。
-
CREATE TABLE BOOL_TEST (bl BOOLEAN);
これで、真理値型の列blを持つテーブルが作られる……かどうかは、実は実装依存です。主要なデータベース製品のうち、現時点でこのDDL(Data Definition Language)が実行できるのは、PostgreSQLとMySQLのみです。ベンダーの3製品(Oracle、SQLServer、DB2)では、いずれも真理値型をサポートしていないためエラーになります(図1)。
図1 BMS 真理値型のサポート状況
DBMS | 真理値型のサポート |
PostgreSQL 8.3 | サポートする。ただし、unknownをNULLで代替する |
MySQL 5.1 | サポートする。ただし、unknownはサポートせず、内部的には0/1の整数値として扱われる |
Oracle 11g | サポートしない |
SQL Server 2008 | サポートしない(ただし、0/1の値を取るBIT型は存在する) |
DB2 9.5 | サポートしない |
しかも、PostgreSQLとMySQLも、真理値を完全にサポートするわけではないのです。どういうことかというと、真理値というからにはもちろんtrueとfalseがあって、その部分のサポートにはどちらも問題ありません。MySQLはこれを0/1で代替しているという細かい問題がありますが、些細なことです。したがって、どちらのDBでも次のINSERT文は問題なく実行できます。
-
INSERT INTO BOOL_TEST VALUES (true);
INSERT INTO BOOL_TEST VALUES (false);
しかし、ここからが厄介な話なのですが、SQLの真理値には、上記2つの値のほかに、unknown(不明)という3番目の値があります。MySQLはこの第3値をサポートしませんし、PostgreSQLはこれをNULLで代用するという明らかに間違った独自仕様を採用しています[2]。
次のINSERTは、PostgreSQLでもMySQLでもエラーになります。
-
INSERT INTO BOOL_TEST VALUES (unknown);
なぜunknownが存在し、NULLとは扱いが異なるのか
なぜSQLがunknownという奇妙な値を持っているかという理由は、本稿では詳細は省略しますが、重要な結論だけを述べると、NULLとunknownはまったく別物であり、これらを混同してはならない、ということです。
というのも、unknownというのはそもそも、値ではないNULLと通常の値を比較できないために(しかたなく)持ち込まれた真理値であるからです。じゃあNULLは何なのか、という疑問が当然出ると思いますが、これに対する答えは、NULLとは「ここには値がない」という文(statement)だ、というものです。ただ、画面の表示上、「ここには値がない」という文章では幅を取るので「NULL」という簡潔なマークで代用しているだけです。これがなんとなく人間の目にはデータの値のように見えてしまうのは、ただの錯覚です。
したがって、せっかく真理値型をサポートするという先駆的な仕事をしてくれたPostgreSQLには悪いのですが、NULLでunknownを代用しては本末転倒です。
逆にこの観点から見ると、なぜデータベースがいずれも真理値型という基本的なデータ型のサポートに消極的か、という理由もほぼ推測がつきます。それは、unknownがあるからです。
世の中の大半のプログラマやSEは、真理値といえばtrueとfalseの2値しかないと考えています。そこに3値目を持つSQL独自の真理値型を導入したら、混乱を招くのは必定(ひつじょう)です。何しろ、図2に示すように、3値の論理演算は2値の論理演算に比べて非常に複雑で、すっと直観的に把握できるものではありません。ANDとORの演算の組み合わせ数は、2値論理の22=4から、32=9と倍以上に増えてしまいます。
それに加え、3値目のunknownがNULLと勘違いされやすいときています。こうしたいくつもの悪条件によって、どのデータベースも、SQLに真理値は「なかったこと」にしたいという気持ちが生まれても、無理からぬところはあります。