初心者が論理設計を勉強したお話

## 記事の対象者
・ER図や正規化はざっくり理解している方
・論理設計を行う手順を参考にしたい方

## 参考にしたもの
ITメディア：[若手プログラマー必読！５分で理解できるER図の書き方５ステップ](https://it-koala.com/entity-relationship-diagram-1897#i-7)
YouTube：[小学生でもわかるデータベース設計入門。実際に設計しながら基礎を学ぼう](https://www.youtube.com/watch?v=Yg546Zua39A)
Udemy：[はじめてのテーブル設計・データベース設計【わかりやすい解説 + 身近なテーマでレッスン】](https://www.udemy.com/course/hajimete-ronrisekkei/)

## 結論
**エンティティの抽出〜ER図作成までの手順は人それぞれである。
自分がやりやすいフレームワークを作っていくとよい。**

私は上記の資料を参考に自分が一番理解しやすい方法を組み合わせました。
そもそも正規化って何？エンティティって何？という方は上記資料に詳しく説明がありますのでご参考ください。

## 手順
**①エンティティの抽出
②エンティティの属性を決める
③主キーを決める
④テーブルの中からマスタ系テーブルに切り分けられるものを探す
⑤第一正規化を行う（１セル１データにする）
⑥第一正規化で分けたテーブルに含めた方がいい属性を移動させる
⑦トランザクション系テーブルに外部キーを設定する
⑧第三正規化まで満たしているか確認する**

## ①エンティティの抽出
意識するポイントは２つあります。
**①ユースケースから抜き出す
②要件定義やワイヤーフレームから抜き出す**

例えば、題材が出金伝票ならば、①のポイントで考えると、
**出金日に社員が勘定科目を出金する**　システムとなります。
ユースケースは5W1H（いつ、どこで、誰が、何を、なぜ？、どのように）を考えると良いです。
特に、**いつ・誰が・何を・どのように**を考えるとエンティティを抜き出しやすくなります。
以上のことから、{出金日}{社員}{勘定科目}{出金}がエンティティとして抽出されました。

次に②のポイントで考えると、（要件定義・ワイヤーフレームがなくてすみません・・・よくある伝票を想像してもらえれば幸いです）
{勘定科目}{摘要}{コード}{金額}{支払先}などが記載されていると思うのでそれらをエンティティとして抽出します。

①と②を踏まえて、
{出金日}{社員}{勘定科目}{出金}{摘要}{コード}{金額}{支払先}をエンティティとして抽出しました。

## ②エンティティの属性を決める
要件定義やワイヤーフレームからエンティティの属性（カラム）になるものを検討します。
先ほど出したエンティティで同じレベル感のものがあればそれらも統合していきます。
この時点でエクセルなどを使用してテーブルを作成していくとイメージしやすいです。

例えば、こんな感じです。
上から、出金に関係するもの、社員に関係するもの、支払先に関係するものと分けてみました。のちのち、正規化すれば分離していくのでざっくりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/c6f6f3dd-3d67-b0c6-0422-e8d434c0705f.png)

## ③主キーを決める
各テーブルで主キーになりそうなものを検討します。
ポイントは２つあります。
**①重複しないもの（氏名、配達希望日などは重複する可能性あり）
②変更しないもの（商品名、数量などは変更する可能性あり）**

これ２つを満たす条件のカラムがあれば主キーにします。なければIDカラムを作成します。
例えば、こんな感じです。
（今回、勘定科目に対するコードは変更の可能性があるとして主キーから除外しています。）
（出金伝票に勘定科目記述欄がたくさんあると仮定しています。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/8d1ceb35-c525-db1f-e6f0-2f8aa71d0fb6.png)


## ④テーブルの中からマスタ系テーブルに切り分けられるものを探す
このテーブルから正規化を行います。
この作業自体は第二正規化や第三正規化にあたりますが、筆者は**マスタ系データになるものを探す**という方法がやりやすかったのでその方法で正規化していきます。
私の中で、**マスタ系とは電話帳やカタログなどのような、ユーザーがアクションを起こす時に使用する元データとなるものというイメージ**です。
一方、トランザクション系とは出金伝票や注文票などのような、ユーザーがアクションを起こして記録するデータのことだとイメージしています。
ここら辺は自己流で解釈しているので、詳しくは参考文献をみていただけると幸いです。

長くなりましたが、例えば、こんな感じです。
コードや勘定科目って事前に作成しておいて、ユーザーが出金伝票を作成する時に元データとして使用すると思います。そのため、マスタデータとなりえるため、今回その２つを別テーブルへ分けました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/519ff6e3-303a-834e-60b0-9a77dc3dbb35.png)

## ⑤第一正規化を行う（１セル１データにする）
本来、正規化は順番にやるのがセオリーなのですが、ここで第一正規化します。
第一正規化とは１セルに１データとなっている状態です。
また、この時点で１セルに２データ以上含まれているカラムがある場合は、多対多の関係であることが多いです。
多対多の場合はアンチパターンとなりますので、中間テーブルを作ります。

例えば、こんな感じです。
勘定科目テーブルを第一正規化しました。同じIDになっているので見分けがつきにいくいですが、次の手順で多対多が解消されていることがわかるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/ad1c1f5e-94cf-d30c-162b-da8d05e63dd4.png)

## ⑥第一正規化で分けたテーブルに含めた方がいい属性を移動させる
マスタデータを一意にすることができたら、次は作った中間テーブルに含めた方がいい属性がないか検討します。

例えば、こんな感じです。
{摘要}{金額}を出金内訳テーブルへ移動しました。これで出金内訳IDが分かれば、対応する勘定科目と摘要と金額がわかるようになりました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/461df340-84e9-c723-3441-2d0a9c5e506e.png)

## ⑦トランザクション系テーブルに外部キーを設定する
次に外部キーを検討していきます。
外部キーはトランザクション系テーブルのみでOKです。
再度確認すると、**トランザクション系とは出金伝票や注文票などのような、ユーザーがアクションを起こして記録するデータのイメージです。**
外部キーはそのデータを特定するために必要な要素を考えると良いです。

例えば、こんな感じです。
使用していないマスタデータをどこに使用するかで考えました。社員マスタデータと支払先マスタデータは出金に関するテーブルで使用するとよさそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/02cba5ad-0ce1-4725-bd5d-d847b639ecd5.png)

## ⑧第三正規化まで満たしているか確認する
最後に確認します。
ここで、コードテーブルが残っているのでそれについて検討します。
コードは勘定科目を特定するものです。つまり、コードNoが分かれば勘定科目が分かるという関係になります。
一方でコードNoは変わる可能性があるとして主キーとせず、テーブルを切り分けました。
**1対1の関係でテーブルを切り分けた場合は、親テーブルと子テーブルの関係に着目し外部キーを設定します。**

前述の通り、コードNoが分かれば勘定科目が分かるという関係のため、コードテーブルが親・勘定科目テーブルが子です。そのため、親テーブルに外部キーを設定します。
親子関係ができたので、出金内訳テーブルの外部キーも親テーブルのコードIDに変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/197a7265-418d-543d-da34-125d80cf4deb.png)

## ER図
ER図も作成しました。
エクセルでテーブルを作ってみるとアソシエーションも考えやすくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1705928/313d57b9-2fa7-cbc7-d350-be67ab40985e.png)

## おわりに
私の今のレベル感だとこのような手順が一番しっくりデータベース設計を行うことができました。今後はこの手順で行いながら修正していきさらにいい手順を見つけたいです。
人それぞれ知識のレベル感や考え方のクセなど違うと思いますので、自分に合った方法を探してみてください。
誰かの手順の参考になれば幸いです。