Hot Heart, Cool Mind.

会計×IT の深層へ

渡辺幸三氏の「動的参照関係」について

関西IT勉強宴会メーリングリストで、渡辺幸三氏が提案している「動的参照関係」について話題となっていたのだが、この概念についての理解がかならずしも共有されていないような気もしている(勘違いであればご免なさい)。

渡辺氏がブログで挙げている説明では、動的参照関係の説明のために、主に有効期間付きのマスタが例に採られている。一方、有効期間付きのマスタの設計は、昔から色々な考えが交錯し、業務システム設計の経験をある程度積んできた人ならば誰もがこれについては一家言持っている、といったテーマでもある。

そのため、私見ではあるが、動的参照関係の説明に有効期間付きのマスタを用いると、有効期間付きのマスタの是非や設計に関して百家争鳴状態になってしまい、動的参照関係じたいの意義になかなか議論が及ばないような気がするのである(有効期間付きのマスタについて、私が仕事を始めた四半世紀前!と今とで、基本的に同じような議論がなされていること自体、アプリケーション設計に関する知識が十分に確立されていないことの証左でもあって、それはそれで嘆かわしい事態だと思うが、これはまた別の問題でもある)。

私自身は、動的参照関係を、よくあるわりに見落としがちで、かつ、便利な概念であると考えているので、これは残念な状況である。

実際、有効期間付きのマスタ以外にも、動的参照関係を適用可能な場面はあるので、そういった例で説明することも、動的参照関係の理解につながるのではないかと思い、このエントリを書いてみることにした。

参考:動的参照関係に関する渡辺氏のエントリ


動的参照関係とは

顧客別に配達方法を登録する、というケースを考える。配達方法には「通常」「特急」等があり、それぞれ、標準配達日数や料金が異なる。標準配達日数や料金は、もちろん、配達方法だけでなく顧客の所在地域によっても異なる。また、地域によっては一部の配達方法が適用されない場合もある。例えば、関西地域については、(たぶん大阪にある当社本社から近距離であるため)「特急」は適用されない。
顧客登録に際しては、顧客の所属地域について誤解が無いよう(三重県は関西地域か?)、顧客の居住する都道府県を登録して貰い、その都道府県から地域を決定することにする。なお、都道府県が属する地域は変更されることがある(三重県は中部地域から関西地域に変更されるかもしれない)。その場合、その都道府県を居住地とする顧客に対する標準配達日数と料金は、新地域に合わせて変更となる。

以上の要件をみたすマスタテーブル設計の一例が以下に示されている。各テーブルの主キーは、項目名を [ ]- で括って示している。なお、実際の設計では、地域や顧客に対して識別のためのコードなり、(ユーザの目から隠れた識別子である)サロゲートキーなりを割り当て、それらを主キーとすることになる。その選択自体、議論の対象となり得るが、ここでの議論には係わりがないので、下記例では、名称を主キーとしている。

(1)地域別配達方法マスタ

各地域と、その地域に適用可能な配達方法の組合せを指定するとともに、その地域・配達方法によって定まる標準配達日数・標準配達料金を示す。

[ 地域,  配達方法 ] - 標準配達日数,  標準配達料金
関西, 通常 1, 300
中部,  通常 3, 300
中部,  特急 1, 600

(2)都道府県マスタ

当社の配達サービスにおいて、各都道府県がどの地域に属するとみなされるかを示す。

[ 都道府県 ] - 地域
大阪府 関西
三重県 中部

(3)顧客マスタ

各顧客の所在地の含まれる都道府県と、所望する配達方法を示す。

[ 顧客 ] - 都道府県, 配達方法
X氏 大阪府, 通常
Y氏 三重県, 通常
Z氏 三重県, 特急

顧客マスタを画面に表示する際には、都道府県をもとに決定された「地域」、および、地域と配達方法で決まる「標準配達日数」と「標準配達料金」も、確認のため表示したい。そこで、これらの導出項目も含めて記述すると、顧客マスタは以下の通りとなる(導出項目は括弧書きする)。なお「導出項目」は実際のテーブル上には保持されない(照会時に導出される)。

[ 顧客 ] - 都道府県,  配達方法,  (地域),  (標準配達日数),  (標準配達料金)
X氏 大阪府, 通常, (関西), (1), (300)
Y氏 三重県, 通常, (中部), (3), (300)
Z氏 三重県, 特急, (中部), (1), (600)

さて、ここで、大阪府のW氏を新たに登録する。配達方法は「特急」を適用するとしよう。

[ 顧客 ] - 都道府県,  配達方法,  (地域),  (標準配達日数),  (標準配達料金)
X氏 大阪府, 通常, (関西), (1), (300)
Y氏 三重県, 通常, (中部), (3), (300)
Z氏 三重県, 特急, (中部), (1), (600)
W氏 大阪府, 特急, (関西), ?,

ところが、実は、W氏を上図4行目のように登録することはできない。大阪府は関西地域であり、関西地域では配達方法として「特急」は提供されないからだ。
別の言い方をすれば、登録できないのは、上図のW氏の行の、地域と配達方法の組合せが、地域別配達方法マスタに存在しないからである。

お気づきのように、これは外部キー制約と似ている。地域と配達方法が外部キーとなって地域別配達方法マスタを参照している。ただし、一般の外部キー制約とは異なる点もある。外部キーを構成する項目のひとつである「地域」が、導出項目なのである(「都道府県」から導出されている)。

通常の外部キー制約と同様に、この制約はいくつかの局面に適用される。

① 顧客マスタの登録時および、行修正時

上で見たように、登録しようとしている顧客の都道府県をもとに決定される地域と配達方法の組合せが、地域別配達方法マスタに存在することが要請される。

② 地域別配達方法マスタの、行削除時

削除しようとしている地域と配達方法の組合せを、(都道府県マスタ経由で間接的に)参照している行が、顧客マスタに存在しないことが要請される。

都道府県マスタの、行修正時

都道府県の所属地域を変更した場合に、顧客の所属地域と配達方法の組合せが必ず地域別配達方法マスタに存在する、という状態が保たれることが要請される。

上記の要請③は、通常の外部キー制約には無いものである。上図の例で、都道府県マスタ上で「三重県」が所属する地域を「中部」から「関西」に変更するとしよう。このとき、導出項目を含む顧客マスタ上で、Y氏・Z氏の地域が「関西」に変更される(脚注①)。そして、地域別配達方法マスタには、「関西」と「特急」の組合せは存在しないので、Z氏の行は制約違反となる。ゆえにこの変更は許されない(この変更に先だって、Z氏の配達方法を「通常」に変更しなければならない)。

こうしたチェック(特に最後に挙げたチェック)を実際にきちんと行うのは、システム開発上、それなりの手間がかかる。手間だけの問題ではなく、見落としてしまうこともあり得る。そういう意味で、このような制約は、本当は、データベース管理システム(DBMS)側で簡単に適用できるようにして欲しいものである(脚注②)。それが期待できないのであれば、アプリケーションフレームワーク等のインフラでサポートするのが望ましい。
なお、画面や帳票の表示の際には、動的参照関係を辿ってテーブルをジョインする必要があるが、そうしたジョインを自動化することだけが問題なのではない。それにとどまらず、動的参照関係に伴う制約(拡張された外部キー制約)への違反行為をきちんとチェックできることが重要である。アプリケーション開発の労力の多くは、こうした地味なチェック処理を含む、ユーザの関心にのぼりにくい「配管工事」に費やされるのだから。

以上の議論は、外部キーを構成するすべての項目が導出項目である場合にも、もちろん、当てはまる。要は、導出項目を含む複数の項目からなる外部キーによって作られ、制約を伴う参照関係を、「動的参照関係」と呼ぶのである。なお、上記の例では、外部キーを構成する導出項目である「地域」は、他のテーブル(都道府県マスタ)とのジョインによって得られるが、このことは、動的参照関係の要件ではない。他の項目からもっと複雑な操作を経て導出されても構わない。

動的参照関係の使いどころ

前出の例は、動的参照関係の概念を示すには適切だが、その有用性を説得するという面では、いくぶん心もとない。あらためて動的参照関係の使いどころを挙げてみよう。渡辺氏が例示している有効期間付きマスタに対する参照関係への適用は、典型的な適用ケースと思うが、それ以外にも、例えば、組合せパターンに対する制約の表現に用いることができる。少し抽象的な言い方だが、A と B の組み合わせを指定する場合に、組み合わせ可能なパターンが、A, B 少なくとも一方について、分類を用いて指定される場合である。以下のような例がある:

  1. 生産管理システムの部品表(BOM:Bill of Materials)において、親品目と子品目の組合せに制約がある場合。… 「完成品」は親品目を持てない。「中間組立品」の親品目は「部品」ではあり得ない、等
  2. 在庫管理システムにおいて、品目分類と、その品目分類の品目を在庫可能な倉庫施設のタイプの間に制約がある場合。…生鮮食品は専用の倉庫施設にしか在庫できない、等
  3. 会計システムにおいて、部門の分類と、その部門で使用可能な勘定科目の組合せに制約がある場合。…「広告宣伝費」「販売促進費」勘定は、営業部門でしか使えない、等

部品表の例で説明しよう。ディスクリート型(部品組み立て型)の製造プロセスにおける部品表は、完成品を頂点に、中間組立品(アッシーとかユニットとも呼ばれる)、部品等、様々な種類の品目がぶら下がったツリー構造をなしている。こうしたツリー構造を表現するのが、ふつう「品目構成」とか「部品構成」と呼ばれるマスタテーブルで、単純化すれば以下のような構造をしている:

(1)品目構成マスタ

[ 親品目,   子品目 ] -  原単位
A製品  , Xユニット 4
A製品  , Yユニット 1
Xユニット, イ部品   2
Xユニット, ロ部品   1

「原単位」は、親品目1単位あたりでみた、各子品目の必要量のことである。

このテーブルを辿れば、A製品1台の組み立てには、Xユニットが4個必要であり、Xユニット1個にはイ部品が2個必要・・・といった具合に、完成品を頂点とした品目ツリー(すなわち部品表)が表現されていることが明らかだろう。

ここで、各品目は「完成品」「ユニット」「部品」いずれかであるとする。各品目がいずれであるかは、品目マスタ上の属性項目「品目タイプ」で識別される:

(2)品目マスタ

[ 品 目 ] - 品目タイプ
A製品 完成品
Xユニット ユニット
Yユニット ユニット
イ部品 部品
ロ部品 部品

これにより、品目構成マスタ上の導出項目として、(品目マスタから導かれる)「親品目タイプ」「子品目タイプ」を置くことができる。

(1')品目構成マスタ:導出項目付き

[ 親品目,   子品目 ] -  原単位,  (親品目タイプ),  (子品目タイプ)
A製品  , Xユニット 4, (完成品), (ユニット)
A製品  , Yユニット 1, (完成品), (ユニット)
Xユニット, イ部品   2, (ユニット), (部品)
Xユニット, ロ部品   1, (ユニット), (部品)

さて、以上の準備の上で、親品目と子品目として組合せ可能な品目のタイプに、次の制約があるとしよう:
  1. 完成品は親品目を持てない。
  2. ユニットの親品目はユニットまたは完成品でなければならない(部品は不可)
  3. 部品の親品目は、完成品・ユニット・部品、いずれでもかまわない。

この制約に基づき、許容される親品目タイプと子品目タイプの組合せをテーブルにすると以下の通りである。

(3)親子品目タイプ組合せマスタ

[ 親品目タイプ,  子品目タイプ ]
完成品  ユニット
完成品  部品
ユニット  ユニット
ユニット  部品
部品  部品

品目構成マスタ上の「親品目タイプ,子品目タイプ」が親子品目タイプ組合せマスタを動的に参照すると定義すれば、上述した組合せ制約に違反する行が品目構成マスタに存在し得ないことを保証することができる。ためしに「イ部品-Yユニット」の親子関係を品目構成マスタに登録することを試みよう:

(1'')品目構成マスタ:導出項目付き(制約違反データ追加)

[ 親品目,   子品目 ] -  原単位,  (親品目タイプ),  (子品目タイプ)
・・・
イ部品  , Yユニット 1, (部品), (ユニット)
・・・

親子品目タイプ組合せマスタには、(親品目タイプ,子品目タイプ)=(部品,ユニット)の組合せが無いので、上図の行は存在が許されない(従って登録できない)ことが明らかである。

動的参照関係の適用ケースはこうした組合せ制約の実現に限られるわけではないが、一方で、このような制約が課せられるケースは、結構、普通にあるのではないかと思う。

終わりに

データベースの設計といえば、正規化ばかりが強調されるが、実際には正規化を尽くした上になお残るデータ間の制約というものが多々あって、本エントリで挙げたのはそのいくつかの例に過ぎない。実際、正規化の基礎概念である「関数従属性」は、制約の一種に他ならないが(脚注③)、すべての制約を関数従属性に分解できるわけでもない。これは、リレーショナルデータベースの生みの親であるE.F.コッド博士自身が、リレーショナルデータベースに関する最初の論文においてすでに認識していたことである。(脚注④)

そうした、正規化理論の手の内に収まらない制約を、どのように拾い上げ、かつ、実装していくかは、業務システム開発において、目立たないが重要なテーマである。
制約を実装できるかどうかを問題にしているのではない。SQLで実装すべきか、ホスト言語側で対応すべきかといった実装手法を問題にしているのでもない。実装は今でもできるし、手法も色々ある。ただし、多くの場合、手続き的なプログラムコードを積み重ねることになる。これが問題である。こうした手続き的記述の実装には手間がかかり、かつ、極めて検証しにくいのである(特にユーザにとっては)。

だから、実装方法いかんに依らず、ユーザやその代理としてのアプリケーション設計者の側で、この項目とこの項目の間に、たとえば「動的参照関係」がある、と指定しさえすれば、後のチェック処理やジョイン処理に関しては、具体的な手続きの記述を要求することなく、拡張されたデータベース管理システムとでもいうべきフレームワークが面倒を見て欲しいのである。このとき、ユーザはあくまで、データ間に、あるパターンのロジカルな関係が存在するという認識あるいは要請を記述するのであって、その要請が満たされているかをチェックする手続きを記述するのではないことが肝心である。こういう記述の仕方を「宣言的記述」と呼ぶ(これについては渡辺氏のブログ記事を参照されたい)。

アプリケーションの設計・開発において、このように、宣言的に記述すればことが済むという領域を増やしていけば、前述したような、ユーザの目に映りにくい配管工事的なプログラム開発は減り、ユーザと開発者の距離がもっと縮まる。

そのような世界を実現するためには、業務システムに存在する種々の制約をパターン化して、簡潔に記述できるようにすることが、明らかに必要である。渡辺氏の動的参照関係はその重要なステップとなり得ると思う。休日をつぶして、私が、長々とした文章を書く理由もそこにある。

渡辺氏の取り組まれている XEAD Driver も、このような文脈で捉えることができる、すなわち、既存のRDBでは対応されていないこうしたデータ制約をパターン化し、宣言的に記述することで、アプリケーション開発のかなりの部分を占める、制約遵守を保証するためのプログラムコードを除去するという方向性の上にある、と理解している(XEAD Driver には他の要素もあるが)。

プログラムの自動生成は有用である。しかしもっと本質的なのは、アプリケーションの仕様や制約をパターン化し、ユーザに対しても(ある程度容易に)伝達できる形で宣言的に記述することである。これができれば、自動化はある意味すでにわれわれの手中にある。だから、単なる自動生成ではなく、制約指向の自動生成であることがポイントなのだ。
制約をパターン化できさえすれば、その記述形式を設計することは容易だろう(言語形式であれ、表形式であれ)。こういった記述形式は、昨今のシステム開発コミュニティでのホットトピックである「DSL(Domain-specific Language : ドメイン特化言語)」に他ならない。DSLの豊かなテーマが、目の前のごく普通の業務システムの中に眠っている、と考えると、技術者・アプリケーション設計者としての血が騒がないだろうか。
こうしたことも含めて、私としては、制約指向、ならびにそれを具現化しようとしている XEAD Driver とそのコンセプトに対する理解者が増え、その方向性がシステム開発の世界で現実のものとなっていくことを願っている。

最後に、私は、三重県にたいして、なんら偏見を持っているわけではないことを付言しておく。




(脚注①)
このように、参照側の行に変更が無くとも他のテーブルの変更に伴って導出項目を含む外部キーが変化してしまう(従って異なる行を参照先とするようになる)ことから、渡辺氏はこれを「動的」参照関係と呼ぶのだと推察する。

(脚注②)
動的参照に伴う制約は、ビューに対する外部キー制約である。私の知る限り、例えば、Oracle 10g ではビューに対する外部キー制約を登録することが可能だが、実行プランの最適化のために用いられる程度で、実際には制約として機能しない(本文中に記述したようなチェックは行われない)。

(脚注③)
例えば、テーブルR上で関数従属性A→Bが存在するとしよう。この関数従属性は「Rにおいて、相等しいAを持つ行が複数あるならば、その各行のBは必ず相等しい」という制約と解釈できる。われわれが通常思い浮かべる正規化されたテーブルでは、主キーを決定項とする関数従属性しか存在しないため、この制約は常に満たされる(相等しい主キーを持つ行は、常に1行しかないからである)。すなわち、主キーに関する一意性制約により、主キーを決定項とする関数従属性制約は必ず満たされる。だから、われわれは、通常、関数従属性が制約であることを意識せずに済むのである。

(脚注④)
ここでリンクされている論文「A Relational Model of Data for Large Shared Data Banks」では「関数従属性」という用語はまだ用いられていないが、論文中で博士が扱っている冗長性(=本エントリでいう「制約」)の例は、関数従属性の枠内で収まらないものがほとんどであり、すでにこの論文執筆時点で、博士はそのような制約への対処(宣言的記述での対処)を強く意識していたと、容易に推定できる。