関係データベースの第三正規形を扱う
第三正規形は別の列を経由して決まる列を分ける
関係データベースの正規化で、第二正規形の次に置く段階が第三正規形 (Third Normal Form, 3NF) である。
2NF では、キー以外の列が、行を区別するキーの一部だけで決まることはない。それでも、キー以外の列が別のキー以外の列を経由して決まる重複は残る。3NF は、その重複を別の表へ移す。
行を他の行と区別する列の組を候補キーと呼ぶ。候補キーがキー以外の列を決め、その列がさらに別のキー以外の列を決めることを推移的関数従属と呼ぶ。店舗名が 注文ID から直接ではなく 店舗コード を経由して決まる、というのがその例である。3NF は、2NF であり、この推移的関数従属がない状態である。
注文表の店舗名を店舗の表へ移す
第二正規形の注文表では、1行を区別する候補キーが 注文ID だけである。キーが1列なので、キーの一部だけで決まる列はない。
| 注文ID | 店舗コード | 店舗名 |
|---|---|---|
| 1 | S10 | 東店 |
| 2 | S20 | 西店 |
| 3 | S10 | 東店 |
この表では、列ごとに、何が分かれば値が決まるかが違う。
- 店舗コードは
注文IDだけで決まる。注文 1 の店舗コードは S10 である。 - 店舗名は
店舗コードだけで決まる。店舗コード S10 は、どの注文でも東店である。注文IDが店舗コードを決め、その店舗コードが店舗名を決める。
店舗名は店舗の表へ移す。店舗コードは、注文がどの店舗のものかを示す列として注文の表に残す。
注文の表では、注文ID が分かれば店舗コードが1つに決まる。
| 注文ID | 店舗コード |
|---|---|
| 1 | S10 |
| 2 | S20 |
| 3 | S10 |
店舗の表では、店舗コード が分かれば店舗名が1つに決まる。S10 の東店は、注文のたびに書かなくてよい。
| 店舗コード | 店舗名 |
|---|---|
| S10 | 東店 |
| S20 | 西店 |
2つの表を 店舗コード でつなぐと、分ける前の行に戻る。注文 1 は店舗コードが S10 なので、店舗名は東店になる。
第三正規形でもキーの一部を決める重複は残る
表を分けると、値の直し方と追加の仕方が単純になる。
- 店舗名を直すときは、店舗の表の1行を直せばよい。S10 の注文が2件あっても、2行とも直す必要はない。
- まだ一度も注文していない店舗も、店舗の表へ追加できる。
- ある店舗の注文をすべて消しても、店舗名は店舗の表に残る。
ここまでの表では、キー以外の列は、その表のキー以外の列を経由せずに決まる。それでも、候補キーの一部になっている列が、キーではない別の列だけで決まる重複は残ることがある。次の割当表は、キー以外の列がなく、3NF である。
| 学級 | 科目 | 教室 |
|---|---|---|
| 甲組 | 数学 | 北棟 |
| 乙組 | 数学 | 北棟 |
| 甲組 | 英語 | 南棟 |
1つの科目の教室は1室で、1室で行う科目は1つとする。行を区別する候補キーは (学級, 科目) と (学級, 教室) の2つある。科目も教室も、どちらかの候補キーに入っている。キー以外の列はないので、推移的関数従属はない。
数学の教室は北棟で、学級が2つあるので北棟が2行に書いてある。科目が分かれば教室が決まるが、科目だけでは行を区別できない。北棟を別の教室に直すときは、数学の行をすべて直す必要がある。
科目が教室を決めるこの関係は、決める側が候補キー全体ではない。決まる側の教室は候補キーの一部なので、3NF の条件には引っかからない。ボイス・コッド正規形で分ける対象になる。3NF が整えるのは、キー以外の列が、キー以外の別の列を経由せずに決まるところまでである。