DB設計

#   導入

##  要約
この記事では、データベース設計の基本原則やキーの種類、制約の役割について解説しています。特に、カラムは細かく分割し、親子関係を正しく管理することが重要とされています。主キーはナチュラルキーかサロゲートキーを目的に応じて選び、制約でデータの整合性を保ちます。また、テーブル名やカラム名の命名規則も説明され、リレーションの数学的背景にも触れています。

##  核心
### カラムはなるべく細かい単位にしろ
-   意味的に分割できるなら、分割する
-   例：名前(name) → 姓(last_name) + 名(first_name)
-   理由
    -   「山田太郎」「山田 太郎」など、表記の差異が一意性を壊す恐れがある
    -   「阿倍仲麻呂」や「源義経」など姓名の区切りがわかりにくい人がいる
    -   並べ替え・検索・外部連携が柔軟になる

### 孤児を生むな
-   **カスケード**を行う。
    -   子供(外部キー)→親(主キー)の順に*削除する*
    -   子供(外部キー)→親(主キー)の順に*変更する*

### 主キーを可変長文字列にする場合は、固定長文字列＋表記体系を厳格に定めろ
-   表記ゆれや同じ意味でも表記が異なる場合はあると、主キーの役割がなくなる

### 主キーはナチュラルかサロゲートか、目的に応じて選べ
-   ナチュラルキー：ユーザーに意味がある（例：社員番号, 学籍番号）
-   サロゲートキー：システム的に安定（例：自動採番ID、UUID）
-   どちらを使うかはプロジェクトの要件・規模次第。

### 列の意味を変更するな
-   体重のカラムに年齢や身長のデータを入れるな。
-   当たり前過ぎてこれ以上は書かない。

### 同じテーブルを量産すな。１つだけにしろ
-   同じ役割のテーブルは１つでいい。そのまま。
-   table_aとtable_bで同じ場合は、データ精査(**データクレンジング**)を行い、1つのテーブルにする。
-   システム統合で発生する可能性がある。


#   本文
##  テーブル

![テーブルの構成](https://kk-blog.tech/article_img/table.png)

-   実務では、「属性」とは言わない。レコードや列と言った方が伝わる。


##  テーブルの種類

###  マスタテーブル
- システム利用開始時の段階から入っていないと困るデータをもつテーブルのこと。
- 単に「マスタ」と呼ばれることが多い。

### トランザクションテーブル
- システムを利用していく中で、蓄積されていくデータをもつテーブルのこと。


##  キー

```
スーパーキー ⊃ 候補キー ⊃ 主キー  (1つ選ばれる)
                    　 ⊃ 複合キー(複合選ばれる)

[スーパーキー]
 ├─ 候補キー
 │   ├─ 主キー（1つ選ばれる）
 │   │   └─ 複合キーのこともある（複数列）
 │   └─ その他の候補キー（ユニークな列）
 └─ 超過列を含むキー
```
### スーパーキー
-   レコードを一意に識別できる任意の列の組み合わせ。
-   候補キーよりも広い概念。つまり、候補キー＋不要な列も含む。
-   *あまり業務では重要な役割を果たさないから、そういうものがあるのか程度に*
-   例：社員番号（候補キー）や 社員番号 + 氏名（スーパーキー）


### 候補キー
-   主キーになり得る列（または列の組）。
-   テーブル内でレコードを一意に識別できるすべてのキーの候補。
-   主キーはこの中から1つ選ばれたもの。
-   *あまり業務では重要な役割を果たさないから、そういうものがあるのか程度に*
-   例：社員テーブルで「社員番号」　「メールアドレス」の両方が一意なら、どちらも候補キー。


### 主キー(primary key)
-   テーブルにおいて**必ず1つのみ存在**し、各レコードを**一意に識別**（**unique**）できる列。
-   NULLは不可、重複も不可。
-　 自動的に **NOT NULL** ＋ **UNIQUE** を含む
-   例：社員番号、ID、マイナンバーなど。

-   主キーには、**ナチュラルキー**と**サロゲートキー**の２種類ある。
    -    ナチュラルキー（Natural Key）
         -    実世界で意味のある情報を使ったキー
         -    例：社員番号、メールアドレス、ISBN、国コードなど
         -    ユーザーにとっても意味がある（覚えやすい）

    -    サロゲートキー（Surrogate Key）
         -    システムが内部的に割り当てるID
         -    例：自動採番の整数ID（id）、UUIDなど
         -    ユーザーにとっては意味がない

    | 概念       | 用語      | 特徴                 |
    | -------- | ------- | ------------------ |
    | 意味のある主キー | ナチュラルキー | 実世界に意味があり、ユーザーに優しい |
    | 意味のない主キー | サロゲートキー | システムが生成、安定性と柔軟性が高い |


### 複合キー
-   複数の列を組み合わせて一意に識別する主キーのこと。
-   つまり、そのテーブルには、その組み合わせは他に存在しないということ
-   例：注文ID + 商品ID → 注文詳細テーブルでの主キー。


### 外部キー
-   他のテーブルの主キーを参照するキー。
-   リレーション（関連）を作るために使用され、参照整合性を保つ(**参照整合性制約**)。
-   設定した外部キーが主キーを参照する性質のことで、*必ず主キー側は存在している*。
-   例：ordersテーブルのcustomer_idが、customersテーブルのidを参照。
    -   外部キー(複数) → 主キー(一つ)
-   参照される主キーを*親*とすると、参照する外部キーを*子供*と見ることができる。
    -   主キーと外部キーは*親子関係*と同じ
    -   *独身*（＝子供を持たない親）は存在しても問題ない。
    -   *親が存在しないのに子供が存在する*ことは、参照整合性違反となる。
    -   つまり、親子関係があるのに「親が削除されたのに子供が残っている」といった状態は許されない。
    -   この場合は、*親子ともに削除*か、*子供をNULLにして親を削除する*。
    -   親が削除されたときにその子供を削除する動作を**カスケード**という。
    -   親を変更したときも同様である。

##  制約
-   制約とは：テーブルに保存されるデータに対して「守るべきルール」を設定するもの。
-   不正なデータを事前にブロックすることで、データの一貫性や正確性を守る。

### NOT NULL制約（ヌル禁止）
-   列に NULLを許さない（必ず値が入っている必要がある）
-   よく主キーや必須入力項目で使われる

### 一意制約（UNIQUE）
-   重複を禁止する制約
-   主キーと違い、NULLは許容される場合がある
-   例：メールアドレスや電話番号など

### CHECK制約
-   値の範囲や条件を指定できる
-   条件を満たさないデータの登録を防ぐ
-   例：年齢(0～120歳)

## 命名
-   テーブル名・カラム名には以下の文字のみを使用すること
    -   半角アルファベット（a～z, A～Z）
    -   半角数字（0～9）
    -   アンダースコア（_）

-   名前の先頭は必ずアルファベットにする。

-   重複する名前を付けない
    -   同一テーブル内で同名のカラムは定義できない。
    -   同一スキーマ内で同名のテーブルは定義できない。

-   テーブル名は原則、**複数形**または**集合名詞**で命名する
    -   例：users, orders, products
    -   ただし、実際の現場では「複数形にしない」　「英語の文法的な複数形ではない」ケースも多く、**組織ごとの命名規則に従うことが最も重要**である。


##  【おふざけ】リレーション
-   ここ、数学ガチ勢が本気出すゾーンです。
-   調べてみたら、見事に心が折れました。ここはもう大学数学（集合論など）で地獄。
-   なので今回は、雰囲気だけつかむ作戦でいきます。

### リレーションは、「n項関係（n-ary relation）」
-   リレーションは、数学における「n項関係」ってやつが元ネタ。
-   結論：「テーブル」と「表」は似て非なるモノ！
    -   リレーションとは、「1つのテーブル（構造とデータ）を数学的に定義したもの」であって、「テーブル同士の関係」じゃない。
    -   重複レコードはない。
    -   レコードに順番はない。
    -   カラムの並び順も意味なし。

### ちょっとだけ集合論っぽい前提知識
-   集合とは？
    -   同じ要素を何回入れても「1個」になる！（例：{(1, 2), (1, 2)} = {(1, 2)}）
    -   順番は関係ない！集合は「順序不同」。順番が変わっても同じ集合。

-   直積ってなに？
    -   複数の集合から要素を1つずつ取り出して、全部の組み合わせを作ったもの！
    -   例：A = {1, 2}, B = {a, b}の直積(A × B)
        -   A × B = { (1, a), (1, b), (2, a), (2, b) }

-   リレーションとは？
    -   上の「直積」から、実際にあるデータだけを選んだ部分集合。

-   部分集合(⊆)とは、2つの集合A，Bがあって，AがBの一部分であるという状態のこと。
    -   つまり、集合AとBの間には包含関係があるということ。

### リレーションの定義（ちょっとだけ数学風）
```
リレーション R(A₁, A₂, ..., Aₙ) は以下のように定義される：

R(A₁, A₂, ..., Aₙ) ⊆ dom(A₁) × dom(A₂) × ... × dom(Aₙ)
```
-   R：テーブルの名前（社員、商品など）
-   A₁〜Aₙ：属性（カラム）の名前（社員番号、名前など）
-   dom(Aᵢ)：各属性が取りうる値（ドメイン）

### 実際に考えてみよう！
1.  道具をそろえる
    -   リレーション名 R
        -   テーブルのようなものの「名前」です（例：社員、顧客など）
    -   属性名 A₁, A₂, ..., Aₙ
        -   テーブルの「列名」みたいなものです（例：社員番号、名前、年齢 など）
    
    -   ドメイン関数 dom
        -   各属性が取りうる値の「集合（ドメイン）」を教えてくれる関数です
        -   例：dom(社員番号) = {1001, 1002, ...}, dom(年齢) = {0, 1, 2, ..., 120}

2.  直積を作る
    -   「リレーションは、属性ごとのドメインからなる直積の有限部分集合」と言ってます。
    -   具体的に言うと：dom(A₁) × dom(A₂) × ... × dom(Aₙ)
    -   つまり、「属性A₁の値」と「属性A₂の値」...のすべての組み合わせ（全パターン）を考えるということです。

3.  そのうちの一部だけを使う（部分集合）
    -   実際にテーブルとして存在するデータ（リレーション）は、その「全部の組み合わせ」ではなく、実際に登録されているデータ（行）だけです。
    -   したがって、「リレーション R(A₁, A₂, ..., Aₙ) は、直積 dom(A₁) × dom(A₂) × ... × dom(Aₙ) の有限部分集合」という言い方になる。


### 結論：表とはまるで違う
| 特性              | 原因（数学的な理由）       |
| --------------- | ---------------- |
| **重複レコードなし**    | 集合だから、同じタプルは1個まで |
| **レコードに順番がない**  | 集合は順序を持たないから     |
| **カラムの順番も意味なし** | リレーションは、属性名（名前・年齢など）によって定義されているから |

-   「リレーション ≠ 表」
-   「Excelの表っぽいけど、実は全然違う」
-   ここまで読んで「ふーん」ってなった人、正解です。
-   無理に理解しなくても、今は「Excelの表と違うらしい」くらいでOK！



#   出典

- IBM「リレーショナル・データベース構造」
    - [https://wa3.i-3-i.info/diff1116table.html](https://wa3.i-3-i.info/diff1116table.html) （アクセス日：2025年5月14日）

- ORACLE 「いまさら聞けない！？Oracle Database設計」
  - [https://www.oracle.com/jp/a/tech/docs/technical-resources/dbdesign.pdf](https://www.oracle.com/jp/a/tech/docs/technical-resources/dbdesign.pdf) （アクセス日：2025年5月14日）

- Wikipedia 「表 (データベース)」
  - [https://ja.wikipedia.org/wiki/%E8%A1%A8_(%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9)](https://ja.wikipedia.org/wiki/%E8%A1%A8_(%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9)) （アクセス日：2025年5月14日）

-  釣りキチプログラマー翔平の備忘録 「主キー、候補キー、外部キー、スーパーキーなどのいろんなキーについて」
   -  [https://poppingcarp.com/various_key/](https://poppingcarp.com/various_key/) （アクセス日：2025年5月14日）

-  SRA OSS Tech Blog 「増永教授のDB特論④「候補キーの見つけ方」」
   -  [https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-4/](https://www.sraoss.co.jp/tech-blog/db-special-lecture/masunaga-db-special-lecture-4/) （アクセス日：2025年5月14日）

-  ITの学び 「データベースは主キー、外部キー、候補キー、代理キー、複合キーなどキーがいっぱい！」
   -  [https://itmanabi.com/db-key/](https://itmanabi.com/db-key/) （アクセス日：2025年5月14日）

-  Qiita 「DB設計　サロゲートキーとナチュラルキー」
   -  [https://qiita.com/masapiko/items/05c393379c2eb42c86f5](https://qiita.com/masapiko/items/05c393379c2eb42c86f5) 

-  TiDB Docs 「オブジェクトの命名規則」
   -  [https://docs.pingcap.com/ja/tidbcloud/dev-guide-object-naming-guidelines/](https://docs.pingcap.com/ja/tidbcloud/dev-guide-object-naming-guidelines/) （アクセス日：2025年5月14日）

-  増永 良文 「リレーショナルデータベース入門: データモデル・SQL・管理システム・NoSQL」
   -  [https://www.amazon.co.jp/%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E5%85%A5%E9%96%80%E2%80%95%E3%83%87%E3%83%BC%E3%82%BF%E3%83%A2%E3%83%87%E3%83%AB%E3%83%BBSQL%E3%83%BB%E7%AE%A1%E7%90%86%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%BBNoSQL-Information-Computing-%E5%A2%97%E6%B0%B8-%E8%89%AF%E6%96%87/dp/4781913903?&linkCode=sl1&tag=glassoniosdia-22&linkId=02db5412e9ca92abcd6ec021e1f1efba&language=ja_JP&ref_=as_li_ss_tl](https://www.amazon.co.jp/%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E5%85%A5%E9%96%80%E2%80%95%E3%83%87%E3%83%BC%E3%82%BF%E3%83%A2%E3%83%87%E3%83%AB%E3%83%BBSQL%E3%83%BB%E7%AE%A1%E7%90%86%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%BBNoSQL-Information-Computing-%E5%A2%97%E6%B0%B8-%E8%89%AF%E6%96%87/dp/4781913903?&linkCode=sl1&tag=glassoniosdia-22&linkId=02db5412e9ca92abcd6ec021e1f1efba&language=ja_JP&ref_=as_li_ss_tl) （アクセス日：2025年5月14日）