データベース

データベースの正規化をわかりやすく解説!!

今回はデータベースの正規化について解説します。
正規化の問題は基本情報処理試験、応用情報処理試験によく出題されます。
基本的には非正規形~第3正規形までを理解しておくとよいです。


関係データベースとは

関係データベースとはデータを複数の表(テーブル)として管理し、行(レコード)と列(フィールド、属性)で表同士の関係を定義することで複雑なデータの関係性を扱えるようにしたデータベースの管理方式です。
SQLServerやPostgreSQL、Oracleなどが関係データベースに該当します。
基本的に情報処理試験でデータベースといえば関係データベースを表すと思いましょう。

正規化とは

データベースの正規化とはデータの重複を最小限に抑えデータの一貫性や完全性を確保するためのデータ設計の手法です。

非正規形

まずは非正規化の状態のデータがどんなものなのかを理解しましょう。

非正規形の特徴は:
・データが重複している
・1つのセルに複数の値が入っている(繰り返し項目)
・更新や削除で矛盾が起こりやすい
・表形式になっていない
具体的にどんなもの非正規形というか見ていきましょう。

こちらの受注伝票を見てください。
ごくごく普通の受注伝票でありよく見るものかと思います。
しかしこのままでは表形式なっておらずデータベースでは扱いづらいです。
これをまずは表形式にしていきます。

この伝票の主キーは「受注伝票番号」の「T00001」です。
この受注伝票番号に対してまずは1つのレコードとなるようにデータ設計をすると以下の表のように整理できます。

<受注テーブル>

受注伝票番号 受注先名 TEL 住所 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 合計
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 1 S0001 りんご 2 150 300 U0001 肥田商店 2 S0002 みかん 3 50 150 U0002 田野青果 3 S0003 すいか 4 500 2000 U0001 肥田商店 4 S0003 すいか 4 450 1800 U0002 田野青果 5 S0004 かぼちゃ 2 120 240 U0002 田野青果 6 S0005 トマト 5 100 500 U0002 田野青果先 7 S0006 れもん 6 80 480 U0001 肥田商店 5470

このように横に長いレコードになってしまいます。
また、このデータ設計だと項目の「NO」「商品ID」 「商品名」 「数量」 「金額」 「計」 「仕入れ先ID」「仕入れ先」が繰り返し出てきます。
こういった繰り返されている項目を整理していくことが正規化の作業です。

第一正規形

第一正規化で行うことは表の状態にして繰り返し項目をなくすことです。
この受注伝票で繰り返されている項目は「NO」「商品ID」 「商品名」 「数量」 「金額」 「計」 「仕入れ先ID」「仕入れ先」ですのでこれらを一つの列にまとめる(1度しか出てこない)表に整理します。
そうすると下記のような表となります。
<受注テーブル>

受注伝票番号 受注先名 TEL 住所 NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先 合計
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 1 S0001 りんご 2 150 300 U0001 肥田商店 5470
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 2 S0002 みかん 3 50 150 U0002 田野青果 5470
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 3 S0003 すいか 4 500 2000 U0001 肥田商店 5470
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 4 S0003 すいか 4 450 1800 U0002 田野青果 5470
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 5 S0004 かぼちゃ 2 120 240 U0002 田野青果 5470
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 6 S0005 トマト 5 100 500 U0002 田野青果先 5470
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 7 S0005 れもん 6 80 480 U0001 肥田商店 5470

「受注伝票番号」「発注先名」「TEL」「住所」はひとつひとつの行にそれぞれ入った状態にします。

第二正規形

第二正規化は主キーに対して完全関数従属した状態にします。
主キーが決まれば決定するデータとそうではないデータを分けます。
この手順で分けると下記のように<受注テーブル>と<受注明細テーブル>と分けることができます。
メインテーブルと明細テーブルといったよく見る形なのではないかともいます。

<受注テーブル>

受注伝票番号 受注先名 TEL 住所 合計
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 5470

<受注明細テーブル>

NO 商品ID 商品名 数量 金額 仕入れ先ID 仕入れ先
1 S0001 りんご 2 150 300 U0001 肥田商店
2 S0002 みかん 3 50 150 U0002 田野青果
3 S0003 すいか 4 500 2000 U0001 肥田商店
4 S0003 すいか 4 450 1800 U0002 田野青果
5 S0004 かぼちゃ 2 120 240 U0002 田野青果
6 S0005 トマト 5 100 500 U0002 田野青果先
7 S0005 れもん 6 80 480 U0001 肥田商店

第三正規形

第三正規化では、主キー以外、ここでいう「受注伝票番号」以外に依存している値を取り除いていきます。
第二正規形の時点で「商品名」は「商品ID」のみに紐づいた値です。
同様に「仕入先名」も「仕入先ID」のみに紐づいた値です。
「商品名」と「仕入先名」を<受注明細テーブル>から取り除くと下記のように整理することができます。

<受注テーブル>

受注伝票番号 発注先名 TEL 住所 合計
T00001 赤城商事株式会社 090-●●●●-▲▲▲▲ 長野県長野市中御所町2-3-6 5470
 

<受注明細テーブル>

NO 商品ID 数量 金額 仕入れ先ID
1 S0001 2 150 300 U0001
2 S0002 3 50 150 U0002
3 S0003 4 500 2000 U0001
4 S0003 4 450 1800 U0002
5 S0004 2 120 240 U0002
6 S0005 5 100 500 U0002
7 S0005 6 80 480 U0001

<仕入先マスタ>

仕入れ先ID 仕入れ先
U0001 肥田商店
U0002 田野青果先

<商品マスタ>

商品ID 商品名
S0001 りんご
S0002 みかん
S0003 すいか
S0004 かぼちゃ
S0005 トマト
S0005 れもん

このように仕入先、商品をマスタデータにすることができました。
<受注明細テーブル>はこのままでは<受注テーブル>と紐づけることができないため列の先頭に「受注伝票番号」を入れる必要があります。

まとめ

改めてそれぞれの正規化の特徴を整理すると
第一正規化は
・表形式にする
・繰り返しの項目をなくす
・1つのフィールドに1つの値

第二正規化は
・主キーのみに紐づくデータとそうでなものを分離

第三正規化は
・主キー以外の値に紐づくデータを分離
となります。