正規化
リレーショナルデータベース(RDB)での非正規形から第3正規形までの正規化についてまとめます。
テーブルの各要素の名称
正規化に入る前にテーブルの各要素の名称について確認しておきます。
テーブルの各要素は様々な名称で呼ばれることがあります。
- テーブル全体の呼び方
- テーブル、表
- 横方向の行の呼び方
- 行、row、レコード、タップル
- 縦方向の列の呼び方
- 列、column、フィールド
データベースの用語として用いる際は行(row)、列(column)を使用すべきです。

非正規形(Unnormalized form)
第1正規形の規則を満たさない形です。
以下のようなテーブルは正規化されておらず、非正規形と呼ばれます。
赤くハイライトした部分は、1つの行に2つの行が含まれています。この形は第1正規形を満たしていません。
第1正規形については次の節で説明します。
今後はこのテーブルを正規化していきます。
第1正規形(First Normal Form, 1NF)
第1正規化は以下の条件を満たすものです。
Rule 1
各列に含まれる値はそれ以上分けることができない値でなければいけません。
Rule2
Rule3
Rule4
レコード(横の行)の並び順は意味を持ちません。また、カラム(縦の列)の並び順も意味を持ちません。
第1正規形のテーブルは次のようになります。
一行に複数含まれていたデータを分割して2つの行にすることで、第1正規形を満たしました。
下線は主キーを表します。
主キーは以下の条件を満たします。
- 行を一意に識別できる
- Null値をとらない
今回のテーブルはstudent_id
とcourse_id
が決まればすべての行を識別できます。
student_name
などは同じ値をとる可能性があるので、主キーにはなりません。
第2正規形(Second Normal Form, 2NF)
第2正規形は以下の条件を満たします。
Rule1
テーブルは第1正規形を満たす。
Rule2
テーブル内に部分従属性が存在しない。
すなわち、すべての非キー属性が主キー属性に完全に関数従属する。
関数従属性(Functional Dependency)
正規化は関数従属という用語が重要となります。
Aが決まればBも決まるとき、BはAに関数従属するといいます。
A -> Bと表すことができます。
例のテーブルで表すと、student_id
が決まればstudent_name
も決まるので、student_name
はstudent_id
に関数従属するといえます。
また、student_id
->student_name
と表すことができます。
grade
はstudent_id
とcourse_id
の両方が決まれば決定されるので、grade
はstudent_id
とcourse_id
に関数従属するといえます。
また、(student_id, course_id)
-> grade
と表すことができます。
このテーブルに存在する関数従属性は次のようになります。
-
student_id
->student_name
-
course_id
->course_name
-
course_id
->teacher_name
-
course_id
->teacher_phone_number
-
teacher_name
->teacher_phone_number
-
(student_id, course_id)
->grade
部分関数従属性(Partial Functional Dependency)
主キー属性の一部がほかの非キー属性を決定する関数従属性です。
今回の例では、非キー属性のgrade
は主キー属性であるstudent_id
とcourse_id
に完全に従属しているので部分関数従属性を持ちません。
一方で、非キー属性のstudent_name
は主キー属性の一部であるstudent_id
にのみに従属しているため、部分関数従属性を持ちます。
また、非キー属性のcourse_name
、teacher_name
、teacher_phone_number
も主キー属性であるcourse_id
にのみ関数従属しているため、部分関数従属性を持ちます。
従って、このテーブルは第2正規形を満たしていません。
そのため、部分関数従属性を持つ関係を別のテーブルに分割する必要があります。
分割する際は下図のように、青、緑、赤で色分けされた関係に分割します(オレンジ色の関数従属性は後述します)。
分割したテーブルは以下のようになります。
重複する行は取り除きます。
これで部分関数従属性は取り除かれ、第2正規形を満たしました。
第3正規形(Third Normal Form, 3NF)
第3正規形は以下の条件を満たします。
Rule1
テーブルは第2正規形を満たす。
Rule2
テーブル内に推移関数従属性が存在しない。
推移関数従属性(Transitive Functional Dependency)
非キー属性がほかの非キー属性を決定する関数従属性です。
先ほどの図中で示されたオレンジ色のteacher_name
-> teacher_phone_number
という関数従属性がありました。teacher_name
とteacher_phone_number
はどちらも非キー属性です。従ってこの関数従属性は推移関数従属性と言えます。
実は学生テーブルと履修テーブルはすでに第3正規形を満たしています。
教科テーブルのみオレンジ色に示した部分に推移関数従属性が存在します。
そこで、教科テーブルを分割します。
このように分割できますが、teacher_name
は名前が重複してしまう可能性があるので、新しい属性のteacher_id
を用いてテーブルを作成します。
こうすることで第3正規形を満たすことができました。
最終的にはこのように正規化されました。
最後に関数従属性のまとめを記載しておきます。
関数従属性のまとめ
-
関数従属性
- 主キー属性 -> 非キー属性
-
部分関数従属性
- 主キー属性の一部 -> 非キー属性
-
推移関数従属性
-
非キー属性 -> 非キー属性