【SQL書籍勉強会】テーブル設計

## 背景
最終回である今回は「テーブル設計」についてまとめていこうと思います。

＊本記事は私が学習コミュニティで書籍勉強会を企画したときの発表資料です。
企画概要概要は以下の通り。
・スッキリわかるSQL入門を読み、自分なりの解釈でまとめてみる
・メンバー四人で各１章ずつを担当して読み、Qiita等でまとめて発表
・全12章あるので3日程で1周。（今回はラスト第3回目！！）
・著作権/剽窃等は必ず配慮します。もし該当箇所あれば削除/修正しますのでお気軽にご指摘ください。

## データベース設計

まずは結論から。
データベースの設計は以下の流れで実施します。

1. 概念設計
2. 論理設計
3. 物理設計

それぞれについて見ていきましょう！！


### 概念設計

- 要件のヒアリング
　

SQLが書けるだけではデータベースは作れません。
クライアントがデータベースに求めるものをヒアリングしまとめましょう。

・データベースの目的 (何に使うのか、何を実現したいのか)
・最初に求める機能(基本機能+補助機能) (どういう機能か、あることで助かる機能はなにか)
・将来的に追加したい機能 (将来的に実現したいこと、欲しい機能)

→このヒアリングから<b>エンティティ(情報の塊)</b>を抽出する。
エンティティは<b>複数の属性(attribute)</b>を持っている。

*エンティティ：すごいざっくり言うとデータベースのこと。データの塊と表現される。
*属性：データベースのカラムのこと。

例)以下のようなDBが合ったとして、このテーブルのことをエンティティと捉える

|日付|売上|原価|
|---|---|---|
|2021-05-04|10000|3000|
|2021-05-05|20000|6000|
|2021-05-06|15000|4500|

このエンティティや属性、エンティティ同士のリレーションを俯瞰できるようにしたものが<b>ER図</b>なのです！!こういうやつ↓↓
![スクリーンショット 2021-07-23 14.52.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161057/c32aa6bd-0b24-07a4-a78c-e42100548c23.png)

データの関連性とかわかりやすいですよね。

概念設計のまとめ

- クライアントの実現したいことをヒアリングしてまとめる
- まとめた内容からエンティティとして抽出する
- 俯瞰できるようにER図にまとめる

ということだと考えます。

### 論理設計

上記の概念設計はあくまでも理想の構造です。
RDBにそのまま適用できるとは限らないため、使うデータベースで扱いやすい構造にエンティティを加工する必要があります。
これが<b>論理設計</b>です。

やることはこんな感じ。

・多対多を解消するために1対多に分割する作業

・主キーを整理する。主キーを持たない場合は新たにカラム追加したり、不適切なキーが無いか確認したりします。
*主キーは非NULL性、一意性、不変性の３つの特性を持たせるべきです。

・正規化(データの不整合を排除するためにテーブルを分割する)

論理設計において中心となるものが<b>正規化</b>です。
これはデータが矛盾などの不整合/不都合を排除するために実施します。

手順はざっくりと以下の感じです。(詳しく知りたい場合は書籍を見るか、調べてみてください！)

1. 非正規形
整合性が崩れやすい段階。

2. 第1正規形
Excelでいうところの1セルに対して1値が必ず入っている状況
= セルの結合などがない状態

3. 第2正規形
>複合主キーを持つテーブルの場合、複合主キー全体に関数従属すべきである
引用[スッキリわかるSQL入門 p.396](https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB222%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1%E6%B8%85%E5%96%AC/dp/4295005096)


どういうことかというと、
日付というカラムと販路というカラムの２つが複合主キーとなっている場合、部分関数従属的に、主キーの片方だけでデータが呼び出せるような状態を排除すべきということです。

<b>関数従属性</b>：片方の値が決まれば関数的に(自ずと)もう片方の値が決まる関係。
片方と説明しているが、複数になる場合もあるので注意

<b>部分関数従属</b>:主キーが社員IDと部門IDである場合に、部門IDのみで部門名がわかること

|社員ID|部門ID|部門名|氏名|
|---|---|---|---|
|1001|1|営業部|Aさん|
|1002|1|営業部|Bさん|
|2001|2|開発部|Cさん|

４. 第3正規形

>テーブルの非キー列は、主キーに直接、関数従属すべきである。
引用[スッキリわかるSQL入門 p.399](https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB222%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1%E6%B8%85%E5%96%AC/dp/4295005096)

これは<b>推移関数従属</b>いい、以下の表でいうと、社員IDがわかれば部門IDがわかり、部門IDがわかれば部門名がわかるというように、
推移的に関係性がわかるもののことをいう。

|社員ID|部門ID|部門名|氏名|
|---|---|---|---|
|1001|1|営業部|Aさん|
|1002|1|営業部|Bさん|
|2001|2|開発部|Cさん|

要はこれを排除しようぜってことです。


他にも第5正規形まであるらしいので、気になる方は調べてみてください！

### 物理設計

物理設計は最低限の知識として手順だけ。
本来はDBMS製品ごとのもっと深い知識が必要。

・論理設計後に、DBMS製品の選定する
・最終的なテーブル名/列名(物理名)の決定 (*基本アルファベットっで命名)
・制約、デフォルト値の設定
・インデックスの設定(メンバー記事の[SQLのまとめ③(インデックスについて)](https://qiita.com/akihiro-cmd/items/5c702789cac62dbcd39f)を参照)


## まとめ

・データベースの設計は主に３つのフェーズが存在する(概念/論理/物理)
・概念設計ではクライアントのヒアリング、エンティティ抽出、ER図を行う
・論理設計では主に正規化を行う
・正規化によってデータベースに望ましくないもの(１つのセルに複数データ、部分関数従属、推移関数従属)を排除していく
・最後に物理設計でDBMS製品に論理設計を落とし込む


## 参考
・[スッキリわかるSQL入門](https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB222%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1%E6%B8%85%E5%96%AC/dp/4295005096)
・[データベーススペシャリスト試験 正規化を分かりやすく解説 第4回](https://anderson02.com/itshikaku/dbsp/post-745/)
・[AT MARK IT 「関数従属性」を理解する](https://www.atmarkit.co.jp/ait/articles/1703/01/news181.html)


## 書籍勉強会の振り返り

今回書籍勉強会を立ち上げるきっかけである課題の「一人で本を読む非効率性」や「アウトプット機会をつくる」部分はクリアできたように思います。
また、他の人を巻き込む積極性/主体性は自分の武器だと再確認できましたし、勉強仲間を増やすことにも繋がったと感じています。

未経験の学習期間中はどうしてもRubyやPHP等の言語勉強に偏ってしまいますが、こういった勉強会を積極的に行って拾いきれないWEB知識を増やすのは有効だと考えたので、またやってみようと思います！！

参加していただいたメンバーに感謝です！！


## メンバー記事
- [【SQL】トランザクションをマスターしよう！](https://qiita.com/Issei_401/items/fe8725e716c868c2bdc0)
- [【SQL】SQL文を使って対象をロックする方法](https://qiita.com/Issei_401/items/908bd42c2e512a6f81c9)
- [[SQL]SQL入門　- テーブルの作成 -](https://qiita.com/yasu-graz/items/2fd1da10d3cd372ff64b)
- [SQLのまとめ③(インデックスについて)](https://qiita.com/akihiro-cmd/items/5c702789cac62dbcd39f)

## 過去記事
- [【SQL書籍勉強会】SQLとは？](https://qiita.com/vit_udon_husqy/items/8d7e749fd92cde6dafec)
- [【SQL書籍勉強会】SQLの集計](https://qiita.com/vit_udon_husqy/items/3bec7ec5a5a9416e3b61)