今回はデータベースの正規化について解説します。
正規化の問題は基本情報処理試験、応用情報処理試験によく出題されます。
基本的には非正規形~第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つの値
第二正規化は
・主キーのみに紐づくデータとそうでなものを分離
第三正規化は
・主キー以外の値に紐づくデータを分離
となります。