僕なりの DB 備忘録

# 設計手順

DBの設計手順をYoutubeの動画を見て学んだ

> https://www.youtube.com/watch?v=D5UgoChhrSo



## システムの要件を把握

要件と機能を明確にする



## テーブルの概要設計（ラフスケッチ）

シナリオを考えながら思いつく限りのテーブルとカラムを日本語（慣れてきたら最初から英語名）で作る

これExcelだとやりやすいらしい



## テーブルの詳細設計（最終調整）

ここからMysqlWorkbenchを使うといいらしい



### 日本語を英語に変換

日本語名を「論理名」、英語名を「物理名」というらしい

命名規則

- 半角英数、アンダースコア
- テーブル名は複数形、カラム名は単数形



### カラムに型を付ける

`varchar(255)`は大事。256以上だとインデックスが貼れなくなるらしい。

どのテーブルにも、

`id` : プライマリキー、INT型 Auto Increment、プリフィックス不要

`created_at`: datetime型

`updated_at`: datetime型

を追加する



### ER図を書きながら正規化

リレーションを貼っていく。

`1:N`の関係のものは、`N`側に外部キーを持たせる。`テーブル名の単数形_id`みたいな形にする。



### 制約条件やインデックスをつける

インデックス： 検索のキーになるカラムにつける、主キーや外部キーには自動でつくので付けなくてもおｋ

> 例えば、名前で検索したい時などで、`name`カラムにつけたりする、これ必要かな？

制約：NOT NULL、ユニークキー（重複しないものにはできるだけ指定する）、外部キー（リレーション先にレコードが存在することを保証する）



# 正規化



## 第一正規形

横方向の繰り返しをなくす。横方向に同じカラム名を繰り返さない

| ユーザ名 | 商品名 | 単価 | 数量 | 商品名 | 単価 | 数量 | 商品名 | 単価 | 数量 |
| -------- | ------ | ---- | ---- | ------ | ---- | ---- | ------ | ---- | ---- |
| A        | a      | 100  | 1    | b      | 120  | 2    | c      | 150  | 3    |

↓

| ユーザ名 | 商品名 | 単価 | 数量 |
| -------- | ------ | ---- | ---- |
| A        | a      | 100  | 1    |
| A        | b      | 120  | 2    |
| A        | c      | 150  | 3    |

## 第二正規形、第三正規形

どちらも、縦方向の繰り返しをなくす。（なんか推移従属か完全従属かみたいな違いらしいけど、そんなのどうでもいいらしい）

| 注文番号 | 注文日 | ユーザ名 | 住所  | 送料区分 | ***商品名*** | ***単価*** | ***数量*** | 合計金額 |
| -------- | ------ | -------- | ----- | -------- | ------------ | ---------- | ---------- | -------- |
| 0001     | 1/4    | ユーザA  | 住所A | その他   | 商品a        | 100        | 1          | 330      |
| 0001     | 1/4    | ユーザA  | 住所A | その他   | 商品c        | 10         | 3          | 330      |
| 0001     | 1/4    | ユーザA  | 住所A | その他   | 商品d        | 200        | 2          | 330      |
| 0002     | 1/4    | ユーザB  | 住所B | その他   | 商品b        | 50         | 5          | 250      |
| 0003     | 1/5    | ユーザC  | 住所C | 離島     | 商品b        | 50         | 1          | 70       |
| 0003     | 1/5    | ユーザC  | 住所C | 離島     | 商品c        | 10         | 2          | 70       |
| 0004     | 1/8    | ユーザB  | 住所B | その他   | 商品b        | 50         | 5          | 250      |

↓ `1:n`の関係のテーブルに分割する。注文番号をキーとする

| 注文番号 | 注文日 | ユーザ名 | 住所  | 送料区分 | 合計金額 |
| -------- | ------ | -------- | ----- | -------- | -------- |
| 0001     | 1/4    | ユーザA  | 住所A | その他   | 330      |
| 0002     | 1/4    | ユーザB  | 住所B | その他   | 250      |
| 0003     | 1/5    | ユーザC  | 住所C | 離島     | 70       |
| 0004     | 1/8    | ユーザB  | 住所B | その他   | 250      |

| 注文番号 | ***商品名*** | ***単価*** | ***数量*** |
| -------- | ------------ | ---------- | ---------- |
| 0001     | 商品a        | 100        | 1          |
| 0001     | 商品c        | 10         | 3          |
| 0001     | 商品d        | 200        | 2          |
| 0002     | 商品b        | 50         | 5          |
| 0003     | 商品b        | 50         | 1          |
| 0003     | 商品c        | 10         | 2          |
| 0004     | 商品b        | 50         | 5          |

↓ 

まだユーザ情報と商品情報で縦の繰り返しがあるから、`1:N`の関係にテーブルを分割してやる。（第2正規形）

送料区分も縦の繰り返しがあるから、`1:N`の関係にテーブルを分割してやる。（第３正規形）

| 注文番号 | 注文日 | ユーザID | 合計金額 |
| -------- | ------ | -------- | -------- |
| 0001     | 1/4    | Y0001    | 330      |
| 0002     | 1/4    | Y0002    | 250      |
| 0003     | 1/5    | Y0003    | 70       |
| 0004     | 1/8    | Y0002    | 250      |

| 注文番号 | 商品ID | ***数量*** |
| -------- | ------ | ---------- |
| 0001     | S0001  | 1          |
| 0001     | S0003  | 3          |
| 0001     | S0004  | 2          |
| 0002     | S0002  | 5          |
| 0003     | S0002  | 1          |
| 0003     | S0003  | 2          |
| 0004     | S0002  | 5          |

| ユーザID | ユーザ名 | 住所  | 送料区分ID |
| -------- | -------- | ----- | ---------- |
| Y0001    | ユーザA  | 住所A | 01         |
| Y0002    | ユーザB  | 住所B | 01         |
| Y0003    | ユーザC  | 住所C | 02         |

| 商品ID | ***商品名*** | ***単価*** |
| ------ | ------------ | ---------- |
| S0001  | 商品a        | 100        |
| S0002  | 商品b        | 50         |
| S0003  | 商品c        | 10         |
| S0004  | 商品d        | 200        |

| 送料区分ID | 送料区分 |
| ---------- | -------- |
| 01         | その他   |
| 02         | 離島     |



## 注意

楽に扱えるのかどうかを考えながら、マスタとして切り出していく。

正規化しすぎるとアプリケーションコードに落とし込む時につらい。



一対一のものはメインに入れちゃう。



## リレーション

`N:N`の関係のテーブルがあったら、必ず中間テーブルを持たせる。

中間テーブルにはリレーション以外の情報を極力持たせない。持たせても日時関連くらい。