正規化を解説！第１～３正規形、関数従属についても解説！

# 正規化とは？

データベース設計においてデータの**冗長性**を排除して**一貫性**を保つこと。

正規化をすることでデータの重複を減らし、データの更新・削除・挿入時のエラーを防ぐことができます。

正規化には１～５までのレベルが知られていますが、
今回は基本となる第１～３正規形までご紹介致します！

:::note info
### 冗長性とは？

同じ内容のデータが複数のテーブルに保存されていること。
:::

:::note info
### 一貫性とは？

DB内で矛盾が生じている状態で信頼性がなく、
更新時にエラーの原因となります。

例）外部キーに制約が設定されておらず、存在しな user_id が参照できる状態になってしまっている状態。

:::
## 関数従属とは？

正規化の話を進める前に重要なワードとして**関数従属**が存在します。

関数従属とはX列の値が決まればY列の値が一意に決まる関係をいいます。

例えば以下のテーブルの場合、学生IDが決まると学生名は決まるため
学生IDと学生名は関数従属の関係にあります！

```
学生テーブル:
| 学生ID | 学生名   | 学部ID | 学部名   |
|--------|----------|--------|----------|
| 1      | 田中太郎 | 10     | 工学部   |
| 2      | 鈴木一郎 | 20     | 文学部   |
| 3      | 佐藤花子 | 10     | 工学部   |
```


# 第１正規形

第１正規形のルールは一つの列は単一（スカラ）の値を保持しなければならない。
また、各列は同じ種類のデータを持たなければなりません。

- 非正規化テーブル
```
| ID | 名前       | 電話番号             |
|----|------------|----------------------|
| 1  | 田中太郎   | 090-1234-5678, 080-2345-6789 |
| 2  | 鈴木一郎   | 080-3456-7890        |
```
非正規形のテーブルでは電話番号カラムに２つの値が入ってしまっています。
この状態では検索する場合にカンマ区切りをしている箇所に対して複雑な条件設定が必要となりますし、検索結果の検出も誤ったものとなってしまう可能性が出てしまいます。

これを第１正規形に変換してみます。

- 第１正規形に変換
```
| ID | 名前       | 電話番号       |
|----|------------|----------------|
| 1  | 田中太郎   | 090-1234-5678  |
| 1  | 田中太郎   | 080-2345-6789  |
| 2  | 鈴木一郎   | 080-3456-7890  |
```

電話番号の列は単一の値のみ保持するように変換されました！

# 第２正規形

```
学生コーステーブル:
| 学生ID | コースID | コース名   | 学生名   | 年齢 |
|--------|----------|------------|----------|------|
| 1      | 101      | 数学       | 田中太郎 | 20   |
| 1      | 102      | 物理       | 田中太郎 | 20   |
| 2      | 101      | 数学       | 鈴木一郎 | 22   |
```

上記テーブルでは主キーが、学生IDとコースIDの複合キーとなっています。
複合キーに対してコース名はコースIDにのみ依存している状態です。
この状態を**部分関数従属**といいます。
第２正規形では部分関数従属を取り除くためテーブル分割をしていきます。

:::note info
### 複合キー
複数の列を組み合わせて一意のキーを構成するもの。
:::


## 第2正規形テーブル分割の流れ

学生コーステーブルからマスターテーブルであるコーステーブルを切り出し、
学生コーステーブルを中間テーブルとして定義することで第２正規形となります。


1. コーステーブル

```
コーステーブル:
| コースID | コース名   |
|----------|------------|
| 101      | 数学       |
| 102      | 物理       |
```

2. 学生テーブル:

```
学生テーブル:
| 学生ID | 学生名   | 年齢 |
|--------|----------|------|
| 1      | 田中太郎 | 20   |
| 2      | 鈴木一郎 | 22   |
```


3. 学生コーステーブル:

```
学生コーステーブル:
| 学生ID | コースID |
|--------|----------|
| 1      | 101      |
| 1      | 102      |
| 2      | 101      |
```

# 第3正規形

第3正規形の定義としては**推移的関数従属**を取り除くことにあります。
推移的関数従属とは A → B かつ B → C である場合、A → C という依存関係です。
具体例を見てみましょう。

```
学生テーブル:
| 学生ID | 学生名   | 学部ID | 学部名   | 年齢 |
|--------|----------|--------|----------|------|
| 1      | 田中太郎 | 10     | 工学部   | 20   |
| 2      | 鈴木一郎 | 20     | 文学部   | 22   |
| 3      | 佐藤花子 | 10     | 工学部   | 21   |
```

学生テーブルの中には推移的関数従属が存在します。
学部名（A）は学部ID（B）に関数従属します。
学部ID（B）は学生ID（C）に関数従属しています。
学部名は学生IDに A → C のように推移的に依存しています。

推移的関数従属を取り除くためには、再びテーブル分割を行います。

## 第3正規形テーブル分割の流れ

学生テーブルからマスターテーブルである学部テーブルを取り出します。

1. 学部テーブル
```
学部テーブル:
| 学部ID | 学部名   |
|--------|----------|
| 10     | 工学部   |
| 20     | 文学部   |
```

2. 学生テーブル
```
学生テーブル:
| 学生ID | 学生名   | 年齢 | 学部ID |
|--------|----------|------|--------|
| 1      | 田中太郎 | 20   | 10     |
| 2      | 鈴木一郎 | 22   | 20     |
| 3      | 佐藤花子 | 21   | 10     |
```

# まとめ🖊️

ご覧いただきありがとうございました！
正規化について何気なく理解したまま進んできてしまっていたため
改めて復習もかねて記事にしてみました！

関数従属や冗長であるデータ構成が、なぜいけないのか
改めて復習できてよかったです！

何か気になる点や、おかしな点ありましたらお気軽にコメントください！