テーブル設計に必要な正規化

正規化とは?

RDBMS(リレーショナルデータベース)において、テーブルを作成しデータを格納する前に、必ず考えるべきことがテーブルの正規化です。
テーブルの正規化をすることで得られる効果としては以下のようなものがあります。
では、正規化とは何かというと、テーブルに格納するデータをどのように分解して、どのように結び付けるかという事を考えることです。
簡単に例をあげると、以下のようなテーブルがあるとします。
旅行プラン
場所日付人数価格(基本価格に対する倍率)
日光2008/07/051008,400(1.05)
日光2008/07/061208,800(1.10)
日光2008/07/07808,000(1.00)
日光2008/07/08808,000(1.00)
日光2008/07/09808,000(1.00)
伊豆2008/07/051009,450(1.05)
伊豆2008/07/061209,900(1.10)
伊豆2008/07/07809,000(1.00)

この内容を見ると、『場所』に同じ値が複数出てます。
この『場所』にある『日光』を『鬼怒川』に変えようと思った場合、上記例では5レコードの変更が必要になります。

しかし以下のような表にした場合はどうでしょう?
旅行プラン
場所コード日付人数価格(基本価格に対する倍率)
12008/07/051008,400(1.05)
12008/07/061208,800(1.10)
12008/07/07808,000(1.00)
12008/07/08808,000(1.00)
12008/07/09808,000(1.00)
22008/07/051009,450(1.05)
22008/07/061209,900(1.10)
22008/07/07809,000(1.00)
旅行場所
場所コード場所名
1日光
2伊豆
この場合、『場所』を『日光』から『鬼怒川』に変えたいと思った場合、旅行場所テーブルに存在する、
場所コードが1のレコードの場所名を変更するだけで、旅行プランの場所がすべて鬼怒川になります。

この様に、重複した値を分離してテーブルを分けて、コードで分離することが正規化といわれる作業になるわけですが、
正規化には手法があり、第1正規系~第5正規系、ボイス・コッド正規形、ドメイン・キー正規形というものがあります。

一般的に、第1~第3正規形までが行われています。
ボイス・コッド、第4、第5正規形までいくと、テーブルにアクセスするプログラムが発行するSQLの複雑さとの兼ね合いから
第3正規形や第3正規形をあえて第2正規形に戻したりして設計したりしているのが実務上の実体だと思います。

この理由から、このページでは第3正規形までを説明します。
それ以降の正規形については別ページにてわかる範囲で説明しようと思っていますので、そちらを参照していただければ幸いです。
ページ下部にリンクを作成してあります。

非正規形

正規化する前に、非正規形のデータを考えてみます。
実は最初の例にあげた状態のテーブルでは、正規化されてしまっているのです。
これを非正規形で考えると以下のようなテーブルになります。
旅行プラン
場所日付人数価格(基本価格に対する倍率)参加者名
日光2008/07/051008,400(1.05)安藤さん
日光2008/07/051008,400(1.05)渡辺さん
日光2008/07/051008,400(1.05)安部さん
日光2008/07/061208,800(1.10)安田さん
日光2008/07/061208,800(1.10)結城さん

どのあたりが非正規形なのかというと『場所』~『価格』まで、同じ内容が繰り返されていて、
それに付随する『参加者』だけが繰り返されている状態です。
この様に同じデータを繰り返して格納している状態が非正規形になります。

第1正規形

テーブルの値がスカラ値(値のみ)で行データとして重複データが存在しない状態を第1正規形と言われます。
first normal form 略して 1NF と表記されることもあります。

この冒頭のページで示した最初の例のテーブルは実は現状入っているデータとしては第1正規形になっています。
なので、非正規形のデータと合わせて、第1正規形を作ってみます。
行データとして重複が存在していないためです。
また場所の名前が入っていますがこれを「コード」とみなせば第1正規形だとわかるのではないでしょうか?
旅行プラン
場所日付人数価格(基本価格に対する倍率)
日光2008/07/051008,400(1.05)
日光2008/07/061208,800(1.10)
日光2008/07/07808,000(1.00)
日光2008/07/08808,000(1.00)
日光2008/07/09808,000(1.00)
伊豆2008/07/051009,450(1.05)
伊豆2008/07/061209,900(1.10)
伊豆2008/07/07809,000(1.00)
参加者
場所日付参加者名
日光2008/07/05安藤さん
日光2008/07/05渡辺さん
日光2008/07/05安部さん
日光2008/07/06安田さん
日光2008/07/06結城さん
しかし、以下のようなテーブルにした場合は、第1正規形ではありません。
旅行プラン
場所日付人数価格(基本価格に対する倍率)
日光2008/07/051008,400(1.05)
日光2008/07/061208,800(1.10)
日光2008/07/07,2008/07/08,2008/07/09808,000(1.00)
伊豆2008/07/051009,450(1.05)
伊豆2008/07/061209,900(1.10)
伊豆2008/07/07809,000(1.00)

日付テーブルにカンマ(,)区切りでデータが格納されているデータが存在します。
この行は最初に示した例のように、行ごとに日付を持っていれば第1正規形といえる状態になります。
よって、カンマ区切りなど区切り文字を使用して、実際の値を複数持つデータはスカラ値ではないという事も言えます。
この様なデータは繰り返しグループ反復群などと呼ばれています。

第2正規形

第2正規形は第1正規形をさらに分解します。
第2正規形はsecond normal formや2NFと表記されていることもあります。
第2正規形は第1正規形を満たしている事が最低条件になります。
第2正規形はある項目の値が、一つの項目に対応することが条件になります。
よって例のテーブルを第2正規形にすると以下のように分解されます。
旅行プラン
場所コード日付人数価格(基本価格に対する倍率)
12008/07/051008,400(1.05)
12008/07/061208,800(1.10)
12008/07/07808,000(1.00)
12008/07/08808,000(1.00)
12008/07/09808,000(1.00)
22008/07/051009,450(1.05)
22008/07/061209,900(1.10)
22008/07/07809,000(1.00)
場所
場所コード場所名
1日光
2伊豆
参加者
場所コード日付参加者名
12008/07/05安藤さん
12008/07/05渡辺さん
12008/07/05安部さん
12008/07/06安田さん
12008/07/06結城さん

場所テーブルを作成し、場所コードを作成しました。
その場所コードに対して場所名を持っているデータを作成し、
旅行プラン、参加者のテーブルのキー項目と関連を持っています。
この状態が第2正規形になります。
第2正規形の条件として、あるテーブル(この場合、旅行プラン、参加者テーブル)のある項目(場所コード)が決まれば、
場所テーブルを参照することで、場所名が一意に決まることが条件になります。

第3正規形

第3正規形は第2正規形をさらに分解します。
第3正規形はthird normal formや3NFと表記されていることもあります。
第3正規形は第2正規形を満たしている事が最低条件になります。

第2正規形まではキー項目に着目してテーブル分解および関連付を行っていましたが、
第3正規形では非キー項目に着目してテーブル分解および関連付けをします。

この例では、日付によって旅行料金が変動しています。(日付毎に一定倍率が設定されている)
また、その旅行料金を算出する基本料金は場所ごとに設定されています。
そこに注目してテーブルを分割し従属関係を作っていきます。

料金倍率テーブル
日付基本価格に対する倍率
2008/07/051.05
2008/07/061.10
2008/07/071.00
2008/07/081.00
2008/07/091.00
基本価格テーブル
場所コード基本価格
18,000
29,000
旅行プラン
場所コード日付人数
12008/07/05100
12008/07/06120
12008/07/0780
12008/07/0880
12008/07/0980
22008/07/05100
22008/07/06120
22008/07/0780
場所
場所コード場所名
1日光
2伊豆
参加者
場所コード日付参加者名
12008/07/05安藤さん
12008/07/05渡辺さん
12008/07/05安部さん
12008/07/06安田さん
12008/07/06結城さん

ボイス・コッド正規形

ボイス・コッド正規形は第3正規形を強化したものです。
Boyce/Codd normal formやBCNFと表記されていることもある。
ボイス・コッド正規形はほぼ第3正規形と同じですが、
主キー以外からの関連を認めていません。

これについては、今までの例では表せない(すでにBCNFを満たしている)ため、違う例でご紹介します。

社員番号社員名メールアドレス
1安藤さんandow@xxx.com

このテーブルの場合、社員番号と社員名、社員番号とメールアドレス、社員名とメールアドレスという3つの関連が出来ています。
よって、これを分解することでボイス・コッド正規形が出来上がります。
社員番号社員名
1安藤さん
社員番号メールアドレス
1andow@xxx.com

この様に、ボイス・コッド正規形まで行うと、1人の社員情報を引き出すために、複数テーブルを見る必要が出てきます。
そのため、実務では第3正規形までに留めて、データアクセスする際に見るテーブルの数を減らし
人間がわかりやすい様にしていることが多いです。

第3正規形以降について

ボイス・コッド正規形でも触れましたが、実務では第3正規形まで(またはボイス・コッド正規形まで)にとどめておくことが多いため、
第4、第5正規形についてはテーブル設計に必要な正規化~第4、第5正規形~に記述することとします。