【データベース】RDBの正規化を理解する〜第1正規形〜

## はじめに
改めて正規化について学んだので、理解したことをメモとして残したいと思います！


## 正規化とは？
* データの冗長性をなくし、一貫性と効率性を保持するデータ形式のこと
* 正規化には第1正規系~第5正規形まである(基本的には1~3までで十分らしい)

### データの冗長性とは？
複数のテーブルに同じ項目を持つような状態

**冗長性がもたらすデメリット**
* 無駄なデータ領域が生まれる
* 更新処理、削除処理等を行う際に、同じ項目を持つ全てのテーブルに対して実施する必要がある
* 上記のことからデータの不整合が生まれやすい

### 冗長なテーブルの例
**顧客情報と注文情報を持つテーブル**

| 顧客ID | 顧客名   | 顧客住所         | 注文ID | 商品名     | 注文日       |
|--------|----------|------------------|--------|------------|--------------|
| 1      | 田中太郎 | 東京都新宿区     | 1001   | ノートPC   | 2024-01-10   |
| 1      | 田中太郎 | 東京都新宿区     | 1002   | マウス     | 2024-01-11   |
| 2      | 鈴木花子 | 神奈川県横浜市   | 1003   | キーボード | 2024-01-12   |
| 3      | 佐藤次郎 | 大阪府大阪市     | 1004   | モニター   | 2024-01-13   |

同じ顧客情報（名前や住所）が繰り返し記録されている
もし住所に変更があった場合、関連する全てのレコードを更新しなければならない。
他には、住所が少し異なる形式で保存されていた場合
```
顧客住所:東京都新宿区
顧客住所:東京都 新宿区 (スペースが入っている)
```
データの不整合が生まれる恐れがある

## 一貫性とは？
データの整合性がとれている状態
* 正しくデータの登録、更新ができる
* 一意に値、レコードを特定できる
* 不正な値が混入しない
冗長性を排除することで実現できる

## 第1正規系とは？
スカラ値の原則に沿っている状態のこと

### スカラ値とは？
テーブルの表で言うと一つのセルに一つの値しか存在しない状態のこと
具体的にどういうことか？学校のクラス情報を保持するテーブルを例にする

### 非第1正規形のテーブル例（アンチパターン）

#### クラス情報テーブル

| クラスID | クラス名 | 担任教師     | 生徒                       |
|----------|----------|--------------|----------------------------|
| 1        | 1年A組   | 佐藤先生     | 山田太郎, 鈴木花子, 田中次郎 |
| 2        | 1年B組   | 高橋先生     | 佐々木一郎, 伊藤美咲       |
| 3        | 2年A組   | 中村先生     | 木村健太, 渡辺陽子, 山口幸子, 加藤大輔 |

各クラスの担任と生徒を表すテーブル
#### 問題点
* 生徒の列がスカラ値となっていない(クラスに所属する生徒の値が複数入っている)
* 「生徒情報」と「クラス情報」という異なる2つのエンティティが混在している

<details><summary>エンティティとは？</summary>
<h4>「実体」という意味</h4>
<p>現実世界にあるデータの集合体を指す</p>
<h5>物理的実体があるもの</h5>
<p>「生徒」「校舎」</p>
<h5>実体のないもの</h5>
<p>「点数」「授業料」</p>
<p>DBの世界では上記のどちらもエンティティとして定義する</p>
</details>


ではこのテーブルを第1正規形、スカラ値にするにはどうすれば良いのか？

### 第1正規形のテーブル例
* 異なるエンティティである「クラス情報」と「生徒情報」を２つのテーブルに分割する

#### 正規化後のテーブル

**クラス情報テーブル**

| クラスID | クラス名 | 担任教師 |
|----------|----------|----------|
| 1        | 1年A組   | 佐藤先生 |
| 2        | 1年B組   | 高橋先生 |
| 3        | 2年A組   | 中村先生 |

**生徒情報テーブル**

| クラスID | 生徒名   |
|----------|----------|
| 1        | 山田太郎 |
| 1        | 鈴木花子 |
| 1        | 田中次郎 |
| 2        | 佐々木一郎 |
| 2        | 伊藤美咲 |
| 3        | 木村健太 |
| 3        | 渡辺陽子 |
| 3        | 山口幸子 |
| 3        | 加藤大輔 |

クラス情報と生徒情報は「クラスID」で紐づくようにする

クラスとそれに紐づく生徒情報を取得したい場合はJOINで連結する
```sql
SELECT
  クラス情報.クラスID,
  クラス情報.クラス名,
  クラス情報.担任教師,
  生徒情報.生徒名
FROM
  クラス情報テーブル AS クラス情報
JOIN
  生徒情報テーブル AS 生徒情報
ON
  クラス情報.クラスID = 生徒情報.クラスID;
```

これでスカラ値にすることができました。

## 何故、リレーショナルデータベースではスカラ値しか入れてはいけないのか？
**理由: 主キーが各列の値を一意に特定できなくなるから**
正規化前の状態だと、生徒という列に複数の生徒の情報が入っていました。
この状態だと、もしクラスの一人ひとりに紐づく成績の情報を取得したいとなったとき、特定することが難しくなってしまいます。

## 正規化を理解するために必要な関数従属性
関数従属性とは？
Y = f(X)
Xの値が決まればYの値も一つに決まるということ
YはXに従属するということ

### 従属関係
#### 数学
X ⇨ Y

#### DB
クラスID ⇨ 　担任教師
クラスID ⇨  生徒名

このような関係を意識することが大切

## スカラ値だけど、よくないテーブル例
スカラ値にはなっているけど、良くない例があるので紹介します
例えばには、「生徒の数だけ列を増やす」「同じテーブルで生徒の数だけレコードを持つ」といったテーブルになります
### 1. 生徒の数だけ列を増やす
各クラスに所属する生徒を格納するために、生徒ごとに別々の列を用意しています。
これは、スカラ値であるものの、良くない例です

#### クラス情報テーブル（列増加バージョン）

| クラスID | クラス名 | 担任教師 | 生徒1   | 生徒2   | 生徒3   | 生徒4   |
|----------|----------|----------|---------|---------|---------|---------|
| 1        | 1年A組   | 佐藤先生 | 山田太郎 | 鈴木花子 | 田中次郎 |         |
| 2        | 1年B組   | 高橋先生 | 佐々木一郎 | 伊藤美咲 |         |         |
| 3        | 2年A組   | 中村先生 | 木村健太 | 渡辺陽子 | 山口幸子 | 加藤大輔 |

#### 問題点
- **固定された列数**: 列が生徒数に依存してしまう。生徒の数が変わるとその都度、構造を変更する必要がある。
- **データ領域の無駄**: 生徒数が少ないクラスでは空欄が多くなり、データベースの領域が無駄になってしまう。
- **スケーラビリティの欠如**: 新しい生徒を追加するたびに、テーブルの列を変更しなければならないため、管理が大変が大変になる

### 2. 同じテーブルで生徒の数だけレコードを持つバージョン
生徒ごとに別々のレコードを作成しています。クラス情報が重複して格納されてしまい、冗長性が高くなってしまいます

#### クラス情報テーブル（レコード増加バージョン）

| クラスID | クラス名 | 担任教師 | 生徒名   |
|----------|----------|----------|---------|
| 1        | 1年A組   | 佐藤先生 | 山田太郎 |
| 1        | 1年A組   | 佐藤先生 | 鈴木花子 |
| 1        | 1年A組   | 佐藤先生 | 田中次郎 |
| 2        | 1年B組   | 高橋先生 | 佐々木一郎 |
| 2        | 1年B組   | 高橋先生 | 伊藤美咲 |
| 3        | 2年A組   | 中村先生 | 木村健太 |
| 3        | 2年A組   | 中村先生 | 渡辺陽子 |
| 3        | 2年A組   | 中村先生 | 山口幸子 |
| 3        | 2年A組   | 中村先生 | 加藤大輔 |

#### 問題点
- **データの冗長性**: クラス情報（クラス名や担任教師など）が繰り返し格納されることで、データベースのサイズが無駄に増える。
- **更新操作の複雑化**: もし担任教師が変更された場合、同じクラスIDを持つすべてのレコードを更新しなければならなくなり、処理が複雑になってしまう。エラーの原因になりやすい
こういった問題が起きてしまうため、関連する情報を別々のテーブルに分割して管理する必要があります。

## まとめ
今回は第1正規化について学んだことをまとめてみました。
もし間違った部分などあれば教えていただけると幸いです

次の記事はこちら

https://qiita.com/rgj0830/items/e7e38cd69eb581c21146

### 参考文献

https://www.amazon.co.jp/gp/product/B00EE1XPAI/ref=ppx_yo_dt_b_d_asin_title_351_o03?ie=UTF8&psc=1