妥当性のあるデータを追求する
コンピューターはデータの妥当性に対して関心がないのだと思うようになったのは、大学に入学したときのことでした。当時、私はバンド ディレクターから、バンドおよびジャズ バンドの授業を0単位で履修登録してみるよう言われました。彼が言うには、愚かなコンピューターは、0単位の授業を履修する者がいようなどとは思わないし、学部長から上限を超える履修登録の許可をもらうよう通知してくることもない、それでも、その単位は認定される、ということでした。彼の言った通りでした。
好むと好まざるとにかかわらず、我々はコンピューターなしでは暮らしてゆけません。それらによって制約を受けるときは、うまく避ける術を覚え、それらが間違いを犯したときは、それに対処するだけです。ただし、コンピューターは間違いを犯さないということは、あなたも私も知っています。ある人はこう言っています。「コンピューターのせいにする者は2つの間違いを犯している。その間違いの1つは、コンピューターのせいにすることだ。」
コンピューターがその仕事を正しく行うためには、2つのものが必要です。すなわち、信頼性が高く、頼もしい、バグのないソフトウェアと、妥当性のあるデータです。 先日、後者に関する記事を書いたところですが、この記事でもその続きを述べたいと思います。
ドメイン
最近IBMでは、次のような一般的なデータベース用語を使用するよう勧めていますが、それらの用語はおそらく耳にしたことがあることと思います。たとえば、 物理ファイル の代わりに 表、 レコード の代わりに 行、 フィールド の代わりに 列などです。ここで、もうひとつのリレーショナル データベース用語を紹介したいと思います。それは、「ドメイン」というものです。オンラインで見つけた テキストブック を引用すれば、「ドメインは、ある列に格納することが許される一連の許容値です」ということのようです。ドメインの定義として、これ以上に適切なものはないのではないかと私は思います。
一連の許容値を適用することは、そうした許容値の数が少ないときは簡単に行えます。適切な制約を追加するだけで、データベースは無効なデータを受け入れなくなります。次の表定義のIDおよびType列に注目してください。
create or replace table EmployeeMaster
for system name EmpMast
( ID dec(5) primary key check (ID > 0),
Name varchar(16),
Type char(1) check (Type in ('S', 'H', 'T', 'P')),
Salary dec(9,2),
Wage dec(5,2)
)
IDおよびType列の許容値は、簡単に列挙することができます。時間が十分あれば、5桁の正の整数をすべて列挙することもできます。Typeの4つの許容値なら、すぐにも列挙できるでしょう。
しかし、許容値の数が、列挙するのが非現実的か不可能である列についてはどうでしょうか。どのようにしたらよいでしょうか。
その場合は、パターンを見つけます。
たとえば、ある会社の在庫管理の業務を行っていて、在庫品目には、それぞれID番号が付いているとします。この場合、最初に自問すべき質問は、「品目番号のドメインはどのようなものか」です。平易な言葉で言い換えれば、「品目番号はどのような形式になっているか」ということです。
この会社の場合、品目番号は、A、B、Cのうちの1文字に、4桁の数字が続く形式になっているとします。
有効な品目番号 | 無効な品目番号 |
A2157 | 2A157 |
B3200 | C32 |
C0000 | BR549 |
次のチェック制約は、このパターンを適用します。
create or replace table . . .
item char(5)
check (translate(item, 'AA000000000','BC123456789') = 'A0000'),
. . .
TRANSLATE関数は、2つ目の値の中の文字によって3つ目の値の中の対応する文字を置換した後の、1つ目の値を返します。この例では、BとCはすべてAに変換され、1~9の数字は0に変換されます。Aと0、および他のすべての文字は変換されずに残ります。変換された値がA0000である場合は、その品目番号はドメイン内にあることになります。
では、品目番号に2つのパターンがあるとしたらどうでしょうか。前述の形式に準拠するパターンと、もうひとつ、A、B、Cの文字のうちの2文字の組み合わせに3つの数字が続く形式になっているパターンがあるとします。以下は、そのチェック制約です。
item char(5)
check (translate(item, 'AA000000000','BC123456789')
in ('A0000', 'AA000'))
TRANSLATEは、文字を対応する文字に変換し、結果は2つの値のいずれかになります。
もうひとつの例を見てみましょう。名前の妥当性をチェックするものです。人の名前のドメインはどのようなものでしょうか。
英語では、名前はアルファベット文字と2種類の記号(ハイフンとアポストロフィ)から成るのが一般的です。一部の人名には、埋め込みブランクがあることもあります。可能性があるすべての名前をチェックすることできませんが、パターンをチェックすることはできます。以下はその1つのやり方です。
name char(25)
check (translate(name, ' ',
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-''')
= ' '),
TRANSLATEは、すべての大文字、すべての小文字、ハイフン、およびアポストロフィーをブランクに置き換えます。2つ目のパラメーターは3つ目のパラメーターより短いため、システムは2つのパラメーターを必要なだけのブランクで埋めて3つ目のパラメーターと同じ長さになるようにします。名前に、3つ目のパラメーターの中にない文字がある場合、TRANSLATEはその文字をブランクに変換しないため、TRANSLATEは非ブランク値を返すことになります。
もちろん、これで、完全に妥当性が適用されるわけではありません。「JXnD'pt---k」というような名前は許容されるでしょうが、コンピューターが行えるのはその程度です。
お楽しみはこれから
他のリレーショナル データベース管理システムには、制約で正規表現を使用することができるものもあります。たとえば、次のようにしてA0000のパターンをチェックすることができます。
item char(5) check (regexp_like(item,'[A-Z][0-9]{4}'))
DB2 for iでは、他のコンテキストでは正規表現をサポートしていますが、制約で正規表現を使用することはできません(今のところは)。それでも、IBMがこのサポートを追加するのも時間の問題なのではないかと思います。正規表現を使用できれば、TRANSLATEで行うより、パターン マッチをさらに詳細に行えるでしょうが、今のところは、TRANSLATEで行うしかありません。
従来、ミッドレンジのショップは、ファイル メンテナンスおよびデータ入力プログラムで妥当性検査ルーチンを通じてデータの妥当性を適用してきました。これは、精確なデータベースを保守するためには効果的な戦略ではありません。もしそうだったとしたら、過去数十年の間、これほど多くの不正なデータを目にすることはなかったはずです。妥当性検査ルーチンに加えて、制約やトリガーも必要なのです。