ボイス・コッド正規形への分解は、結局どうすればいいのか(1)
正規化理論の教科書では、「第3正規形だが非ボイス・コッド正規形」のデータ構造*1をボイス・コッド正規形に分解すると関数従属性が消滅する、とよく説明される。
このようなデータ構造に実務で出会ったら、どうすればいいのか。
増永良文 リレーショナルデータベースの基礎〈データモデル編〉 にある受講テーブルの例を使って、全2回で考える。
受講:
学生 科目 教官 加藤 人類学 坂本 加藤 西洋史 小林 山田 人類学 本庄 井上 人類学 坂本
前提
ここでは以下の関数従属性が成立しているとする。
{ 学生, 科目 } -> { 教官 }  ※{ 学生, 科目 }は「受講」の複合キー
{ 教官 } -> { 科目 }
つまり
- 1教官は1つの科目しか担当しない。
- 1科目を教える教官は複数いてよい。
更新時異状の確認
いちおう確認。
以下、教官と科目の組み合わせを「講座」と呼ぶことにすると、このデータ構造から生じる更新時異状は以下の通り。
- 追加の異状
- 受講する学生がまだ決まっていない講座は、受講テーブルに追加できない。
- 更新・削除の異状
- 唯一の学生が受講をとり止めたら、講座の存在自体が消滅してしまう。
更新時異状を放置するとアプリケーションが書けないので、どうしても解消しなくてはならない。
例えば、アプリの仕様書に「講座登録画面から、新規の(=まだ受講する学生が決まっていない)講座を追加することができる」とあったとしても、データ構造の都合で実装することができない。
教科書的な分解
そこで教科書的に分解するとこうなる。
講座:
教官 科目 坂本 人類学 小林 西洋史 本庄 人類学 坂本 人類学 受講:
学生 教官 加藤 坂本 加藤 小林 山田 本庄 井上 坂本
この分解により、
{ 学生, 科目 } -> { 教官 }
の関数従属性が消滅している。
それで何が困るかというと、「受講」にルール違反の行=例えば{ 井上, 本庄 } というレコードを挿入されることを、データベースが拒否できない。
挿入されてしまうと講座と受講の自然結合結果はこうなってしまう。
学生 科目 教官 加藤 人類学 坂本 加藤 西洋史 小林 山田 人類学 本庄 井上 人類学 坂本 井上 人類学 本庄
最後の2行がルール違反。
このことから、「第3正規形以上は分解すればいいってものではないので注意しましょう」みたいなことが書いてあっておしまい、というテキストが多い。
渡辺式/T字形ER手法ではどうするか
教科書的な分解では、更新時異状を回避する代わりに、制約(=関数従属性)の消滅を受け入れることが要求されてしまう。
更新時異状は解消しないとアプリが書けないが、制約の消滅はアプリでチェックすればカバーできる。
だから、分解した方がましですよ、ということなのだろう。
このやり方は、実務で使うのはちょっとつらい。
渡辺式やT字形ER手法ならば、問題に対して、関数従属性を維持しつつ更新時異状を回避できる。
別に魔法のような分解方法があるわけではなくて、分解したら情報が消えてしまうので、フィールドなりテーブルなりを追加することで問題を解消するということ。
それを次回書く予定。
*1:非キー項目から、複合キーの一部への関数従属性が存在する第3正規形のデータ構造
*2:私の主戦場であるPostgreSQL/MySQLでこの制約を表現できるだろうか。check節を使わないと無理だろうな。あとで確認する