データベースの「正規化」って、なんだか難しそうな名前ですね。
やっていることは「同じことを何度も書かないように、表を分ける」だけなんだ。お店の注文伝票を例に、一歩ずつ分けてみよう。
なぜ表を分けるの?:更新時の矛盾
ある文房具店では、注文をこんな1つの表で管理していました。
| 受注番号 | 受注日 | 顧客番号 | 顧客名 | 商品番号 | 商品名 | 数量 |
|---|---|---|---|---|---|---|
| 101 | 4/1 | C1 | 山田商店 | P1 | ボールペン | 10 |
| 101 | 4/1 | C1 | 山田商店 | P2 | ノート | 5 |
| 102 | 4/3 | C2 | 鈴木書房 | P1 | ボールペン | 20 |
| 103 | 4/5 | C1 | 山田商店 | P3 | 消しゴム | 8 |
「山田商店」が3回、「ボールペン」が2回出てきます。これが困りごとの原因です。
このように、重複したデータがあるせいで起きる不都合を 更新時異状(更新時の異常)といいます。
- 修正の異状:1か所直し忘れると矛盾する(上の図)
- 追加の異状:まだ注文のない新商品を登録したくても、受注番号がないので行を作れない
- 削除の異状:注文103を削除すると、「消しゴム」という商品の情報まで消えてしまう
そこで、1つの事実を1か所にだけ記録する ように表を分けていきます。これが 正規化 です。
準備:「決まる」関係(関数従属)
正規化では 「Aが決まれば、Bが1つに決まる」 という関係に注目します。これを 関数従属 といい、A → B と書きます。
- 顧客番号 → 顧客名(C1なら必ず山田商店)
- 商品番号 → 商品名(P1なら必ずボールペン)
- 受注番号 → 受注日、顧客番号
- 受注番号 + 商品番号 → 数量
正規化の3ステップ
ステップ1:第1正規形(繰返しをなくす)
紙の伝票では、1枚の中に商品が何行も並びます。このように 1件の中に同じ種類の項目がくり返し並んでいる 状態を 非正規形 といいます。1行1件の形に直し、各セルに値が1つだけ入るようにしたものが 第1正規形 です。冒頭の表がちょうど第1正規形で、主キーは 受注番号+商品番号 の組です。
ステップ2:第2正規形(主キーの一部で決まるものを分ける)
主キーは「受注番号+商品番号」なのに、受注日は 受注番号だけ で、商品名は 商品番号だけ で決まります。このように 主キーの一部だけで決まる 関係を 部分関数従属 といい、これを別の表に分けると 第2正規形 になります。
ステップ3:第3正規形(主キー以外で決まるものを分ける)
受注の表では、顧客名は主キーの受注番号ではなく 顧客番号 で決まります(受注番号 → 顧客番号 → 顧客名)。このように 主キー以外の項目を経由して決まる 関係を 推移的関数従属 といい、これを別の表に分けると 第3正規形 になります。
表が4つに増えちゃいました。かえって不便じゃないですか?
いい視点だね。確かに「注文ごとの顧客名」を見たいときは、表を結合してつなぎ直す手間がかかる。でも、データの矛盾を防げるメリットのほうが大きいから、まずは正規化するのが基本なんだ。
3つの正規形の比較
| 段階 | 取り除くもの | ひとことで |
|---|---|---|
| 第1正規形 | 繰返し項目 | 1つのセルに1つの値 |
| 第2正規形 | 部分関数従属(主キーの一部で決まる項目) | 複合主キーの「片方」で決まるものを分ける |
| 第3正規形 | 推移的関数従属(主キー以外の項目で決まる項目) | 「キーでない列」で決まるものを分ける |
1・2・3 = 繰返し・部分・推移。「くり・ぶぶ・すい」と唱えて覚えよう。
正規化は 検索を速くするためのものではありません。目的は 重複の排除と、更新時の矛盾の防止 です。「正規化すると表の数が減る」「結合が不要になる」という選択肢は誤りです。
試験に出るポイント
- 正規化の目的は、データの重複をなくし、更新時異状(矛盾)を防ぐ こと
- 第1正規形:繰返し項目をなくす
- 第2正規形:主キーの一部だけで決まる項目(部分関数従属)を別の表へ
- 第3正規形:主キー以外の項目で決まる項目(推移的関数従属)を別の表へ
- 分けた表は、共通の列(外部キー)で 結合 すれば元の情報を復元できる