リレーショナルデータベースの基礎

## 1. リレーショナルデータベースとは？
リレーショナルデータベース（RDB）は、データを **行（レコード）** と **列（カラム）** で構成された **テーブル（表）** に格納し、関係（リレーション）を持たせて管理するデータベースのことです。

### ✅ 特徴
- **データの整合性が保たれる**（一貫性のあるデータ管理）
- **データの冗長性を削減できる**（不要なデータの重複を減らせる）
- **SQL（Structured Query Language）を使用して操作できる**

### 🔍 リレーショナルデータベースの起源
リレーショナルデータベースの概念は、1970年に **エドガー・F・コッド（Edgar F. Codd）** によって提唱されました。彼は、データをテーブルとして整理し、関係（リレーション）を利用することで、効率的なデータ管理ができると考えました。このモデルは現在のほとんどのデータベース管理システム（DBMS）に採用されています。

### 🔗 リレーショナルモデルの基本原則
1. **情報の表現** - すべてのデータは表（テーブル）に格納される。
2. **一意の識別** - 各行は主キーによって一意に識別される。
3. **データの完全性** - 外部キーを使用して整合性を保つ。
4. **操作の一貫性** - データの追加、更新、削除は一貫性を持って行われる。
5. **論理的独立性** - 物理的なデータの構造変更が論理データモデルに影響を与えない。

### 🔥 RDBMS（リレーショナルデータベース管理システム）とは？
RDBMS（Relational Database Management System）は、リレーショナルデータベースを管理するソフトウェアのことです。代表的な RDBMS には以下のものがあります。
- **Microsoft SQL Server**（企業向けに多く利用される）
- **MySQL**（オープンソースで広く使われる）
- **PostgreSQL**（高度な機能を持つオープンソース）
- **Oracle Database**（大規模システム向け）

このように、RDBMS はリレーショナルモデルを実現し、データの効率的な管理を可能にしています。

---

## 2. 基本概念
### 📌 **テーブル（Table）**
テーブルは、データを整理して保存するための構造です。各テーブルは **カラム（列）** と **レコード（行）** で構成されます。

| ID | 名前  | 年齢 | 性別 |
|----|------|----|----|
| 1  | 田中  | 25  | 男  |
| 2  | 鈴木  | 30  | 女  |
| 3  | 佐藤  | 28  | 男  |

### 📌 **レコード（Record）**
テーブル内の各行を指し、個々のデータの集合を表します。
- 例: `1, 田中, 25, 男`（1つのレコード）

---

### 📌 カラム（Column）
カラムはテーブル内の列を指し、特定の種類のデータを格納します。各カラムには **データ型** や **サイズ** などの属性があり、格納できるデータの種類や範囲が決まります。

#### ✅ カラムの基本属性
1. **カラム名** - そのカラムが表すデータの名称（例: `名前`, `年齢`, `メールアドレス`）。
2. **データ型** - 格納するデータの種類（例: 文字列・数値・日付）。
3. **サイズ** - 文字列など可変長データの最大長（例: `VARCHAR(50)` は最大50文字）。
4. **NULL 許可** - データが必須かどうか（`NOT NULL` を指定すると必須）。
5. **デフォルト値** - データが指定されなかったときの初期値。
6. **制約（Constraints）** - `PRIMARY KEY`（主キー）、`UNIQUE`（一意性制約）など。

#### ✅ 主なデータ型

| データ型 | 説明 | 例 |
|---|---|---|
| `INT` | 整数型（符号付き4バイト） | `年齢 INT NOT NULL` |
| `BIGINT` | 大きな整数（符号付き8バイト） | `ユーザーID BIGINT PRIMARY KEY` |
| `DECIMAL(p, s)` | 固定小数点（p桁のうちs桁が小数） | `価格 DECIMAL(10,2)` |
| `VARCHAR(n)` | 可変長文字列（最大n文字） | `名前 VARCHAR(50) NOT NULL` |
| `NVARCHAR(n)` | Unicode対応の可変長文字列 | `メール NVARCHAR(100) UNIQUE` |
| `TEXT` | 大量の文字列（長文） | `コメント TEXT` |
| `DATE` | 日付型（YYYY-MM-DD） | `誕生日 DATE` |
| `DATETIME` | 日時型（YYYY-MM-DD HH:MI:SS） | `登録日時 DATETIME DEFAULT GETDATE()` |

このように、カラムには **データ型・サイズ・制約** などの情報があり、適切に設定することでデータの整合性を保つことができます。  
データベース設計では、各カラムの **データ型の選択** がパフォーマンスにも影響を与えるため、用途に応じて慎重に決めることが重要です。

---

### 📌 主キー（Primary Key, PK）

**主キー（Primary Key, PK）** とは、テーブル内の各レコード（行）を一意に識別するためのカラム（列）です。  
主キーを設定すると、同じ値のデータを重複して登録することができなくなり、データの整合性が保たれます。

#### ✅ 主キーの特徴
1. **一意性（UNIQUE）**  
   - 主キーとして指定されたカラムは、同じ値が重複して登録されることはない。
2. **NOT NULL 制約**  
   - 主キーには `NULL` を含むことができない（必ず値が必要）。
3. **自動的に制約が適用される**  
   - `PRIMARY KEY` を設定すると、`UNIQUE` と `NOT NULL` の制約が自動的に適用される。

#### ✅ 主キーの設定方法

##### 🔹 単一カラムを主キーにする場合
```sql
CREATE TABLE ユーザー (
    ユーザーID INT PRIMARY KEY,
    名前 VARCHAR(50) NOT NULL
);
```
---

### 📌 外部キー（Foreign Key, FK）

**外部キー（Foreign Key, FK）** とは、あるテーブルのカラムが、**別のテーブルの主キー（Primary Key）を参照** することで、データの整合性を維持するための制約です。  
外部キーを設定すると、以下のようなデータの整合性が保証されます。

#### ✅ 外部キーの特徴
1. **参照整合性を保証する**  
   - 参照先のテーブル（親テーブル）に存在しない値を、外部キーに設定することはできない。
2. **親テーブルのデータが削除されたときの動作を制御できる**  
   - `CASCADE`, `SET NULL`, `NO ACTION`, `SET DEFAULT` などのオプションを指定可能。
3. **自動的に制約が適用される**  
   - 外部キーを設定すると、参照元のデータが削除・更新される際の動作が制限される。

#### ✅ 外部キーの設定方法

##### 🔹 単一カラムを外部キーにする場合
```sql
CREATE TABLE 注文 (
    注文ID INT PRIMARY KEY,
    顧客ID INT,
    FOREIGN KEY (顧客ID) REFERENCES 顧客(顧客ID)
);
```
---

### 📌 複合キー（Composite Key）

**複合キー（Composite Key）** とは、**2つ以上のカラムを組み合わせて主キー（Primary Key）を構成する** 仕組みです。  
単一のカラムでは一意性を保証できない場合、複合キーを使用することで、データの整合性を保つことができます。

---

#### ✅ 複合キーの特徴
1. **単独のカラムでは一意性を保証できない場合に使用する**
   - 例えば、`受注ID` 単体では識別できないが、`受注ID` + `商品ID` なら識別可能な場合。
2. **複数のカラムの組み合わせで一意なデータを保証する**
   - 2つ以上のカラムを主キーとして設定することで、データの重複を防ぐ。
3. **外部キーとして他のテーブルで参照可能**
   - **複合キーを持つテーブルのカラムは、他のテーブルの外部キーとしても利用可能**。

#### ✅ 複合キーの設定方法

##### 🔹 **テーブル作成時に複合キーを設定**
```sql
CREATE TABLE 受注明細 (
    受注ID INT,
    商品ID INT,
    数量 INT NOT NULL,
    PRIMARY KEY (受注ID, 商品ID)
);
```

---

### 📌 インデックス（Index）

**インデックス（Index）** とは、データ検索を高速化するために使用されるデータベースの仕組みです。  
インデックスを適切に設計することで、検索パフォーマンスを大幅に向上させることができます。

#### ✅ インデックスの特徴
1. **検索速度の向上**  
   - `WHERE` 句や `JOIN` での検索時に、対象データを素早く特定できる。
2. **データの整合性を保つための補助**  
   - 一意性制約（`UNIQUE`）を持つインデックスは、重複データの挿入を防ぐ。
3. **データの変更（INSERT, UPDATE, DELETE）が遅くなることがある**  
   - インデックスが多すぎると、データ変更時のオーバーヘッドが増加するため、適切な設計が重要。

---

### 📌 **ビュー（View）**
複数のテーブルのデータを仮想的にまとめて扱うための構造。
- 例: `CREATE VIEW 顧客情報 AS SELECT 名前, 年齢 FROM 顧客;`

---

### 📌 トランザクション（Transaction）

**トランザクション（Transaction）** とは、データベースにおける **一連の処理をまとめて管理する仕組み** です。  
例えば、銀行の送金処理では「口座Aから引き出す」「口座Bに入金する」という2つの処理がセットになっていないとデータの不整合が発生します。  
トランザクションを適用することで、一貫性を保ったデータ処理を実現できます。

---

#### ✅ トランザクションの特性（ACID特性）

トランザクションは、**ACID特性** を満たす必要があります。

| 特性 | 説明 |
|---|---|
| **Atomicity（原子性）** | トランザクション内の処理は **すべて成功するか、すべて失敗するか** のどちらかである（途中で一部だけ成功することはない）。 |
| **Consistency（一貫性）** | トランザクション完了後、データベースは常に **整合性のある状態** を維持する。 |
| **Isolation（独立性）** | 複数のトランザクションが並行して実行されても、互いに影響を受けないようにする。 |
| **Durability（永続性）** | トランザクションが **確定（COMMIT）** された場合、その結果は **永続的に保存される**。 |

---

#### ✅ トランザクションの基本操作

トランザクションは、以下の3つの主要なSQLコマンドで管理されます。

| コマンド | 説明 |
|---|---|
| `BEGIN TRANSACTION` | トランザクションの開始 |
| `COMMIT` | トランザクションの確定（処理を保存） |
| `ROLLBACK` | トランザクションの取り消し（変更を元に戻す） |

#### ✅ トランザクションの基本的な使い方

##### 🔹 **成功時（正常にコミットされる例）**
```sql
BEGIN TRANSACTION;

UPDATE 口座 SET 残高 = 残高 - 10000 WHERE 口座ID = 1; -- 口座Aから引き出し
UPDATE 口座 SET 残高 = 残高 + 10000 WHERE 口座ID = 2; -- 口座Bに入金

COMMIT; -- すべての処理が成功したら確定
```

---

## 3. テーブルの関係（リレーション）
### 🔗 **1対1（One to One）**
- 例: **ユーザー** と **ユーザー詳細** の関係
- 1つのユーザーに1つの詳細情報が対応
- データの冗長性を避けるため、個人情報などを分離するケースが多い

```sql
CREATE TABLE ユーザー (
    ユーザーID INT PRIMARY KEY,
    名前 VARCHAR(50)
);

CREATE TABLE ユーザー詳細 (
    ユーザーID INT PRIMARY KEY,
    住所 VARCHAR(100),
    FOREIGN KEY (ユーザーID) REFERENCES ユーザー(ユーザーID)
);
```

### 🔗 **1対多（One to Many）**
- 例: **顧客** と **注文** の関係
- 1人の顧客が複数の注文を持つことができる

```sql
CREATE TABLE 顧客 (
    顧客ID INT PRIMARY KEY,
    名前 VARCHAR(50)
);

CREATE TABLE 注文 (
    注文ID INT PRIMARY KEY,
    顧客ID INT,
    商品 VARCHAR(50),
    FOREIGN KEY (顧客ID) REFERENCES 顧客(顧客ID)
);
```

### 🔗 **多対多（Many to Many）**
- 例: **学生** と **授業** の関係
- 1人の学生が複数の授業を履修でき、1つの授業には複数の学生が参加できる
- **中間テーブル** を用意して管理する

```sql
CREATE TABLE 学生 (
    学生ID INT PRIMARY KEY,
    名前 VARCHAR(50)
);

CREATE TABLE 授業 (
    授業ID INT PRIMARY KEY,
    科目 VARCHAR(50)
);

CREATE TABLE 学生授業 (
    学生ID INT,
    授業ID INT,
    PRIMARY KEY (学生ID, 授業ID),
    FOREIGN KEY (学生ID) REFERENCES 学生(学生ID),
    FOREIGN KEY (授業ID) REFERENCES 授業(授業ID)
);
```

このように、**1対1、1対多、多対多の関係を適切に設計することで、データの整合性を維持し、冗長性を減らすことが可能** になります。


---

## 4. 正規化とは？
### ✅ 正規化の目的
正規化とは、データの **冗長性を排除し、一貫性と整合性を維持するため** のデータベース設計手法です。正規化を行うことで、以下のメリットがあります。
- **データの重複を削減** し、ストレージの無駄を省く。
- **更新時の矛盾（不整合）を防ぐ** ことで、データの整合性を確保する。
- **検索や更新の効率を向上** させる。

### 🔢 正規形の分類
正規化は段階的に進められ、それぞれ **第一正規形（1NF）、第二正規形（2NF）、第三正規形（3NF）** などに分類されます。

#### 🔹 **第一正規形（1NF）** - **繰り返し部分の排除**
##### **第一正規形とは**
**非正規形の表から、繰り返し部分を取り除いたものを第一正規形とする。**

- 横方向に伸びた繰り返しデータを切り離し、縦方向に展開することが必要。
- 計算で求められる列（例: 合計金額など）は不要なため削除。

##### 正規化前のテーブル（非正規形）
| 顧客ID | 名前  | 商品1  | 商品2  | 商品3  |
|--------|------|------|------|------|
| 1      | 田中  | 本   | ノート | ペン |
| 2      | 鈴木  | 消しゴム | - | - |

##### 正規化後のテーブル（第一正規形）
| 顧客ID | 名前  | 商品  |
|--------|------|------|
| 1      | 田中  | 本   |
| 1      | 田中  | ノート |
| 1      | 田中  | ペン |
| 2      | 鈴木  | 消しゴム |

```sql
CREATE TABLE 顧客 (
    顧客ID INT PRIMARY KEY,
    名前 VARCHAR(50)
);

CREATE TABLE 注文 (
    注文ID INT PRIMARY KEY AUTO_INCREMENT,
    顧客ID INT,
    商品 VARCHAR(50),
    FOREIGN KEY (顧客ID) REFERENCES 顧客(顧客ID)
);
```

#### 🔹 **第二正規形（2NF）** - **部分関数従属の排除**
##### **第二正規形とは**
**第一正規形の表から、部分関数従属している列を切り出したものを第二正規形とする。**

- **関数従属:** 主キーが決まると、列の値が一意に定まる関係。
- **部分関数従属:** 複合キーの一部の項目だけで、列の値が一意に定まる関係。

##### 正規化前のテーブル（第一正規形）
| 注文ID | 顧客ID | 顧客名  | 商品  |
|--------|--------|------|------|
| 1      | 101    | 田中   | 本   |
| 2      | 101    | 田中   | ノート |
| 3      | 102    | 鈴木   | ペン |

##### 正規化後のテーブル（第二正規形）
**顧客テーブル**
| 顧客ID | 名前  |
|--------|------|
| 101    | 田中  |
| 102    | 鈴木  |

**注文テーブル**
| 注文ID | 顧客ID | 商品  |
|--------|--------|------|
| 1      | 101    | 本   |
| 2      | 101    | ノート |
| 3      | 102    | ペン |

```sql
CREATE TABLE 顧客 (
    顧客ID INT PRIMARY KEY,
    名前 VARCHAR(50)
);

CREATE TABLE 注文 (
    注文ID INT PRIMARY KEY,
    顧客ID INT,
    商品 VARCHAR(50),
    FOREIGN KEY (顧客ID) REFERENCES 顧客(顧客ID)
);
```

#### 🔹 **第三正規形（3NF）** - **推移的関数従属の排除**
##### **第三正規形とは**
**第二正規形の表から、主キー以外の列に関数従属している列を切り出したものを第三正規形とする。**

- 主キー以外の列に関数従属している列のことを **推移的関数従属** と呼ぶ。

##### 正規化前のテーブル（第二正規形）
| 社員ID | 名前  | 部署ID | 部署名  |
|--------|------|------|------|
| 1      | 佐藤  | 10   | 営業部  |
| 2      | 鈴木  | 20   | 開発部  |

##### 正規化後のテーブル（第三正規形）
```sql
CREATE TABLE 部署 (
    部署ID INT PRIMARY KEY,
    部署名 VARCHAR(50)
);

CREATE TABLE 社員 (
    社員ID INT PRIMARY KEY,
    名前 VARCHAR(50),
    部署ID INT,
    FOREIGN KEY (部署ID) REFERENCES 部署(部署ID)
);
```

### ⚠ **正規化の注意点**
- **過度な正規化はパフォーマンスに影響する** ため、適切なバランスが必要。
- すべてのケースで完全な正規化が最適とは限らず、業務要件に応じたデータ設計が重要。

このように、正規化を適用することで、データの整合性を保ちつつ、無駄なデータの重複を防ぐことができます。

---

## 5. まとめ
✅ リレーショナルデータベース（RDB）は **データをテーブルで管理** する
✅ **主キーと外部キー** を使ってデータの整合性を保つ
✅ **正規化** によりデータの冗長性を削減する