VOLUME 03 / CHAPTER 01

一つの番号で、何を同じものと見なすか

データの意味から候補キーと関数従属を考える。正規化、履歴、SQLの制約を、異なる事実を壊さず管理する設計へつなぐ。

出典照合日: · 独自解説

架空事例:青葉機材の予約明細と機材台帳を扱う。データ、関数従属、識別規則は学習用の仮定である。SQLの具体的な挙動は、明記したPostgreSQL 18の資料と、関係モデルの理論を区別して説明する。

番号は重複していない。それでも二重登録だった

同じ倉庫の同じ機材が、台帳に二行登録されていた。どちらにも違う管理IDが付いている。主キーの制約は守られているのに、貸出し可能な台数が一台多く表示された。

主キーが守ったのは、二つの行の管理IDが重複しないことである。その二行が同じ実機を表していないことまでは、自動的に確かめていない。

機械的に採番する識別子は、行を安定して参照するために役立つ。一方、業務上の重複を判定するには、どの情報が同じなら同じ対象とみなすかを別に定める必要がある。青葉機材では、すべての実機に自社で重複しない資産番号を付けることを前提にする。保存用の管理IDとは別に、資産番号の一意性も守らなければならない。

もし資産番号を倉庫ごとに採番するなら、倉庫番号と資産番号の組が識別の候補になる。どちらが正しいかは、文字列の長さではなく、採用した業務の識別規則で決まる。既存テキスト第17章の候補キーは、この規則から読むと理解しやすい。1

極小であることと、文字数が最小であること

行を一意に識別できる属性の集合がスーパーキーであり、その中で余分な属性を取り除けないものが候補キーである。候補キーが複数ある場合、そのうち一つを主キーとして選ぶ。候補キーの極小性は、属性の一部を取り除くと識別できなくなるという意味であって、文字数や記憶容量の最小性ではない。1

自社資産番号だけで実機を識別できるなら、資産番号と機種名の組も一意ではある。しかし機種名を取り除いても識別できるので、その組は候補キーではない。一方、倉庫ごとの資産番号しかない前提なら、倉庫番号か資産番号の片方を除くと重複する可能性があり、組としての候補キーになる。

その規則が将来も維持されるかも考える。倉庫移動で識別子の一部が変わるなら、取引記録からの参照をどう維持するかが問題になる。人工的なIDを参照用に選ぶ案には、この変更の影響を抑える意味がある。ただし、その選択によって、本来の資産番号の重複を許してよいわけではない。

現在のデータに偶然同じ値がないことも、キーの根拠にはならない。登録済みの機種名がすべて違っていても、将来同名の機種を扱える業務なら、その名前だけに一意性を約束できない。サンプルの観察と、許容するすべての状態についての制約は別である。

関数従属は、データを眺めた印象ではない

予約明細に、予約番号、明細番号、機種番号、機種名、数量、貸出し単価を持たせたとする。同じ予約の中で明細番号は重複しないと決めるなら、予約番号と明細番号の組で一つの明細を識別できる。

また、機種番号が決まれば、現在の機種名が一つに定まるとする。この関係は 機種番号 → 機種名 という関数従属として表せる。矢印は処理の順序でも、値を送信する方向でもない。左の値が同じなら右の値も同じでなければならない、という情報の制約である。1

一つの明細が同じ機種を二台扱うことと、その明細に数量2を保存することは、このモデルでは整合する。しかし、明細ごとに点検状態を持たせると困るかもしれない。二台の個体は、異なる点検状態を持てるからである。どの属性が何によって決まるかを考えると、機種、明細、個体という管理単位の違いが現れる。

まず単位と意味を定め、次に依存関係を考える。その順番を逆にすると、現場の意味に合わない表を、きれいに正規化することができてしまう。

正規化で取り除くのは、更新の矛盾を生む依存

全明細に現在の機種名を繰り返して保存した場合、名称を変更するには、同じ機種の多数の行を更新する必要がある。一部の行だけが更新されれば、同じ機種番号に異なる現在名称が対応してしまう。これが更新異常の例である。

そこで機種番号と機種名を機種表へ分け、明細は機種番号を参照する。名称の更新箇所を一つにできる。予約をまだ受けていない機種も登録でき、最後の予約明細を削除しただけで機種の情報まで失わずに済む。

第二正規形を考えるときは、候補キーの一部だけに依存する非キー属性を調べる。例えば予約番号と明細番号の組が候補キーで、予約受付日が予約番号だけで決まるなら、受付日を各明細へ重ねて持たせる理由を問える。第三正規形では、非キー属性を介する依存など、キー以外の決定関係による冗長性をさらに整理する。1

ただし、「主キーが一列なら正規化は完了」「非キー属性同士の関係をすべて消せばよい」とだけ覚えるのは不十分である。候補キーは、選んだ主キー以外にも存在し得る。正式な第三正規形の条件では、非自明な関数従属 X → A ごとに、Xがスーパーキーであるか、Aがいずれかの候補キーに含まれる属性であるかを見る。BCNFは後者の例外を認めず、非自明な従属の決定側にスーパーキーを要求する。2

この形式的な区別を用いると、似た表を機械的に分割するのではなく、どの依存が問題かを指摘できる。すべての表を小さくすることが正規化ではない。

分ければ元に戻せるとは限らない

担当者、機種、倉庫の対応が、次の三行だったとする。

担当者機種倉庫
甲測定器東
甲発電機西
乙測定器西

これを「担当者と機種」「担当者と倉庫」の二表に分け、担当者で再結合すると、甲には測定器・発電機と東・西の全組合せができる。元にはない「甲・測定器・西」や「甲・発電機・東」まで現れる。

これは本書のデータから直接確かめられる例である。三者の対応を、担当者を共通とする二つの独立した対応へ変えてしまったため、元の関連を復元できなくなった。列を捨てていなくても、対応の情報を失うことがある。

正規化に伴う分解では、必要な情報を結合で復元できるかを確認する。行数が減った、重複文字列が減ったという見た目だけで採否を決めない。依存を各表の制約として検査できるかという観点もあり、正規形の高さだけで全設計の優劣が決まるわけではない。2

同じ住所を二度保存しても、同じ事実とは限らない

顧客の現在住所を顧客表へ集約した。その結果、過去の貸出し契約の届け先まで、住所変更に伴って変わってしまった。ここでは、保存したい事実の意味を取り違えている。

顧客の現在住所と、ある契約で合意した届け先は異なる。値が同じでも、基準となる時点と責任が違う。契約の届け先を取引の属性として保持する設計を、ただちに正規化違反とみなすことはできない。

料金でも同じことが起きる。現在の料金表から算出する見積額と、過去の契約で合意した単価は同じものではない。明細に単価を持つ意味を確かめず、すべて現在の料金表から求め直すと、過去の契約内容を再現できなくなる。

反対に、履歴と名付ければ何でも複製してよいわけではない。訂正の理由、適用開始時点、保持する期間を定める必要がある。本事例では契約時点の値を保持するが、どの項目を履歴化するかは業務要件から決める。データベースは、何を過去の事実として残すかの設計でもある。

型が合っても、制約が不足している

数量を整数型にすれば、小数や文字列との区別はできる。しかし、数量ゼロ、負数、欠落をどこまで許すかは別に定める必要がある。

PostgreSQL 18では、CHECK (quantity > 0) は式が真またはNULLとなる行を許容するため、これだけではNULLを排除できない。必須の正数にしたいなら、NOT NULLも必要になる。また、通常のUNIQUE制約がNULLをどう扱うかは、主キーのNOT NULLと同じではない。PostgreSQL 18には NULLS NOT DISTINCT によって一意性判定のNULLの扱いを変える指定もある。3

外部キーは、参照する値が対応する親のキーと整合するための仕組みである。ただし、親の機材が存在することと、点検済みで貸出し可能であることは別である。参照整合性だけで、任意の業務上の条件を守れるとは限らない。3

例えば、複数の予約行の数量を合計して在庫以下にする制約は、一行の数量が正である条件と違う。PostgreSQLのCHECKへ他行の状態を安易に持ち込んでも、他行の後続変更を含めた保証にはならない。適用できる一意制約、参照制約、排他やトランザクション制御などを、守る条件に合わせて選ぶ必要がある。3

データの正しさは、主キー、正規化、CHECKのどれか一つで完成しない。何を識別し、どの事実を保持し、どの状態を許すかを、それぞれの仕組みへ適切に割り当てる。

知識を答案へ戻す

午前Ⅱ。 候補キーは極小のスーパーキーであり、選択した主キーだけを指すものではない。関数従属は値の制約、DFDの矢印はデータの流れである。正規形の定義と、SQL製品のNULL・制約の挙動を混同しない。

午後Ⅰ。 データ項目の意味と基準時点を問題文から特定する。「住所」と書かれた二項目が現在の連絡先と契約上の届け先なら、同じ値でも統合してよいとは限らない。重複して見えることだけを欠陥の根拠にしない。

午後Ⅱ。 表を分けた事実だけでなく、どの更新異常や履歴の喪失を防ぐためかを説明する。主キーを採番した場合も、業務上の重複をどの条件で防いだかを別に示す。

立ち止まって考える:連番IDがあるのに、同じ機材が二行できた。主キーの故障か

主キーは行のIDの一意性を守っていても、二つの行が同じ実機を表すことを禁止していない場合がある。業務上の識別規則を確かめ、自社資産番号など必要な条件の一意性を別に守る。実データに重複がないことと、将来も一意である制約を区別する。

出典と照合範囲

[1] コンプリートテキスト第4・17・18章、およびIPA「SAシラバス Ver.5.2」5-4、10-3、11-3:管理単位、候補キー、関数従属、論理・物理設計の基礎に接続した。資産番号、契約時点の価格、分解で余分な行が生じるデータは独自の例である。公式シラバス

[2] Rensselaer Polytechnic Institute, CSCI 4380 Database Systems, Normalization(2018):候補キーに含まれる属性、3NFとBCNFの条件、および分解を評価する観点を参照した。本章の三行の表は同資料の転載ではない。授業資料

[3] PostgreSQL 18 Documentation, 5.5 Constraints:CHECKとNULL、NOT NULL、UNIQUE、外部キー、他行を参照するCHECKの制約を照合した。これらの製品上の仕様を、すべてのDBMSの動作として一般化していない。公式文書