satoshi.inoue's blog

備忘録を兼ねているので、薄い内容の投稿もあります。

第1正規形〜第3正規形の手順

スポンサードリンク

非正規形と正規化のメリット

非正規形の特徴

簡単にいうと、正規化が行われていないテーブルを非正規形と呼びます。
例えば、購入履歴を管理するケースを想定して考えてみます。以下は非正規形のテーブル例です。
1回の注文を1行で管理しているため、注文の品が増えるとどんどん横に長くなってしまうという問題があります。

注文番号 注文日 ユーザー名 発送先 送料区分 商品名 単価 数量 商品名 単価 数量 商品名 単価 数量 合計金額
0001 2018/12/31 ユーザーA 住所A その他 商品A 100 1 商品B 50 5 商品D 200 1 550
0002 2019/01/01 ユーザーB 住所B 離島 商品A 100 1 100
0003 2019/01/04 ユーザーC 住所C その他 商品B 50 2 商品C 10 20 300

正規化のメリット

  • データの汎用性アップ
    データが整理されることで、他システムとの連携や移行などが行いやすくなります。
  • データの容量削減
    無駄な重複が削除されることにより、保存に必要なデータ領域の削減になります。
  • データの保守性アップ
    重複したデータがないようにするため、変更がある場合の修正が容易になります。

関数従属性

正規形はテーブルを関数従属性という基準に従って分類する作業である。
これは、もし1つの属性の値がわかれば、常に別の属性の値もわかる、という性質である。関係理論での表記法では、2つの属性の間に矢印を引く。
例えばA → Bは「AはBを決定する」とか「BはAに従属する」と読む。

例)
- 注文番号が分かれば注文日が分かる。
- 商品名が分かれば単価が分かる。

推移的関数従属性

関数従属性が推移的に行われていることを推移的関数従属性と呼びます。

例)
- Xが分かればYが分かる、Yが分かればZが分かる。ただしXが分かってもZは分からない。

第1正規形

横方向の繰り返しの整理をします。 RDBは縦にレコードを追加していく操作には適していますが、カラムは固定なので、横方向の繰り返しを縦に並べるように修正します。

注文番号 注文日 ユーザー名 発送先 送料区分 商品名 単価 数量 合計金額
0001 2018/12/31 ユーザーA 住所A その他 商品A 100 1 550
0001 2018/12/31 ユーザーA 住所A その他 商品B 50 5 550
0001 2018/12/31 ユーザーA 住所A その他 商品D 200 1 550
0002 2019/01/01 ユーザーB 住所B 離島 商品A 100 1 100
0003 2019/01/04 ユーザーC 住所C その他 商品B 50 2 300
0003 2019/01/04 ユーザーC 住所C その他 商品C 10 20 300

これで第1正規形の正規化は完了です。

第2正規形

従属関係にあるデータの分離を行います。

まずは、購入履歴と購入履歴明細に分離します。
<テーブル名: 購入履歴>

注文番号 注文日 ユーザー名 発送先 送料区分 合計金額
0001 2018/12/31 ユーザーA 住所A その他 550
0002 2019/01/01 ユーザーB 住所B 離島 100
0003 2019/01/04 ユーザーC 住所C その他 300

<テーブル名: 購入履歴明細>

注文番号 商品名 単価 数量
0001 商品A 100 1
0001 商品B 50 5
0001 商品D 200 1
0002 商品A 100 1
0003 商品B 50 2
0003 商品C 10 20

さらに、ユーザーデータと商品データに分離できます。
<テーブル名: 購入履歴>

注文番号 注文日 ユーザーID 合計金額
0001 2018/12/31 Y0001 550
0002 2019/01/01 Y0002 100
0003 2019/01/04 Y0003 300

<テーブル名: 購入履歴明細>

注文番号 商品ID 数量
0001 S0001 1
0001 S0002 5
0001 S0004 1
0002 S0001 1
0003 S0002 2
0003 S0003 20

<テーブル名: ユーザーデータ>

ユーザーID ユーザー名 発送先 送料区分
Y0001 ユーザーA 住所A その他
Y0002 ユーザーB 住所B 離島
Y0003 ユーザーC 住所C その他

<テーブル名: 商品データ>

商品ID 商品名 単価
S0001 商品A 100
S0002 商品B 50
S0003 商品C 10
S0004 商品D 200

これで第2正規形の正規化は完了です。

第3正規形

推移的関数従属と呼ばれる従属関係の分離を行います。

ユーザーデータの送料区分を分離します。 <テーブル名: ユーザーデータ>

ユーザーID ユーザー名 発送先 送料区分コード
Y0001 ユーザーA 住所A 01
Y0002 ユーザーB 住所B 02
Y0003 ユーザーC 住所C 01

<テーブル名: 送料区分データ>

送料区分コード 送料区分名称 送料
01 その他 500
02 離島 1000

これで第3正規形の正規化は完了です。

ボイスコッド正規形

主キー以外のカラムが全て主キーに完全関数従属であり、それ以外の従属関係があればテーブルを分離することがボイスコッド正規形の正規化になります。

ユーザーデータにメールアドレスが含まれるとして、登録時に登録済みメールアドレスの再登録をエラーにする処理などを行っていれば、ユーザー名とメールアドレスは1:1の関係にあると言えます。 その場合、ボイスコッド正規形の正規化では、テーブルを2つに分離することになります。 <テーブル名: ユーザーデータ(分離前)>

ユーザーID ユーザー名 発送先 メールアドレス 送料区分コード
Y0001 ユーザーA 住所A A@aaa.jp 01
Y0002 ユーザーB 住所B B@bbb.jp 02
Y0003 ユーザーC 住所C C@ccc.jp 01

<テーブル名: ユーザーデータ(分離後)>

ユーザーID ユーザー名 発送先 送料区分コード
Y0001 ユーザーA 住所A 01
Y0002 ユーザーB 住所B 02
Y0003 ユーザーC 住所C 01

<テーブル名: メールアドレスデータ(分離後)>

ユーザーID メールアドレス
Y0001 A@aaa.jp
Y0002 B@bbb.jp
Y0003 C@ccc.jp

これでボイスコッド正規形の正規化は完了です。

まとめ

正規形で重要なのは第3正規形までで、まれにボイスコッド正規形を利用する機会があります。
本稿で述べたような、横方向に伸ばすようなデータ、重複するようなデータを最適化することが正規化の作業だと考えます。