この章で得られるスキル:
- ✅ ER図の必要性を説明できる
- ✅ エンティティ、属性、リレーションシップを識別できる
- ✅ カーディナリティ(1対多、多対多)を説明できる
- ✅ 多対多を中間テーブルで解決できる
- ✅ ER図からCREATE TABLE文を書ける
- ✅ 要件からER図を作成できる
Step 0: まず体験してみよう
シナリオ:チームでデータベース設計を議論する
ある開発チームで、ECサイトのデータベースを設計することになった。
Aさん: 「商品テーブルと注文テーブルを作ろう」
Bさん: 「注文テーブルに商品名も入れておこう」
Cさん: 「それだと1つの注文で複数商品を買えないよ」
Bさん: 「じゃあ商品1、商品2、商品3の列を作る?」
Aさん: 「それだと4個以上買えない...」
→ 口頭の議論では、全員の認識が食い違いやすい。
ER図で解決
以下のER図を見れば、テーブルの構成と関係が 一目で わかる。
ER図は データベース設計の共通言語 である。
チーム全員が同じ図を見ながら議論することで、認識のズレを防げる。
Step 1: ER図とは
Entity-Relationship Diagram(実体関連図)
ER図 (Entity-Relationship Diagram)とは、データベースの設計を視覚的に表現する図である。
| 要素 | 意味 | 図での表現 |
|---|
| エンティティ | データベースで管理する「モノ」 | 長方形(テーブルに対応) |
| 属性 | エンティティが持つ情報 | エンティティ内の列挙(列に対応) |
| リレーションシップ | エンティティ同士の関係 | 線で結ぶ(外部キーに対応) |
ER図の記法
ER図にはいくつかの記法があるが、本教材では IE記法(Crow's foot記法) を使う。
これは実務で最もよく使われる記法である。
ER図を描くツール
| ツール | 特徴 |
|---|
| Mermaid | テキストからER図を生成。本教材で使用 |
| draw.io | 無料のWebベース作図ツール。直感的に操作できる |
| MySQL Workbench | MySQL付属。既存のDBからER図を自動生成できる |
| A5:SQL Mk-2 | 日本製の無料ツール。ER図作成とSQL実行が可能 |
Mermaidはテキストベースでダイアグラムを記述できるツールである。
本教材のER図はすべてMermaidで描かれている。MarkdownファイルやGitHub上でも表示できるため、チーム開発との相性が良い。
Step 2: エンティティ(実体)
エンティティとは
エンティティ とは、データベースで管理したい「モノ」や「概念」のことである。
ER図では長方形で表現し、データベースの テーブル に対応する。
エンティティの見つけ方
要件から「管理したいモノ」を洗い出す。
例:社員管理システム
- 「社員」を管理したい → employees エンティティ
- 「部門」を管理したい → departments エンティティ
- 「プロジェクト」を管理したい → projects エンティティ
要件の中で 名詞 として登場するものがエンティティの候補になる。
「社員は部門に所属する」→ 社員と部門がエンティティ、「所属する」がリレーションシップ。
Step 3: 属性
属性とは
属性 とは、エンティティが持つ情報のことである。
ER図ではエンティティの中に列挙し、データベースの 列(カラム) に対応する。
属性の種類
| 種類 | 説明 | 例 |
|---|
| 主キー(PK) | エンティティを一意に識別する属性 | 社員ID、注文ID |
| 外部キー(FK) | 他のエンティティへの参照 | 部門ID(社員テーブル内) |
| 一般属性 | その他の属性 | 名前、給与、日付 |
Mermaidでの表現
主キーには PK、外部キーには FK を付記する。
データ型(INTEGER、VARCHAR など)も記載すると、CREATE TABLE文に変換しやすい。
Step 4: リレーションシップ(関連)
リレーションシップとは
リレーションシップ とは、エンティティ同士の関係のことである。
ER図では 線 で表現し、データベースの 外部キー で実現される。
社員と部門の関係
「社員は部門に所属する」という関係をER図で表現する。
departments ||--o{ employees の意味:
|| → departments 側は 1つ(1つの部門に対して)
o{ → employees 側は 0以上(0人以上の社員が所属)
つまり「1つの部門に0人以上の社員が所属する」という関係を表している。
Step 5: カーディナリティ
カーディナリティとは
カーディナリティ とは、リレーションシップの「数の関係」を表すものである。
| 記号 | 意味 | 説明 |
|---|
| ` | | ` |
o{ | 0以上(任意) | 0個でも複数でもよい |
|{ | 1以上(必須) | 少なくとも1つは必要 |
o| | 0または1 | あってもなくてもよい |
代表的なカーディナリティ
1対多(最も一般的)
「1つの部門に複数の社員が所属する」
- 1つの部門 → 0人以上の社員
- 1人の社員 → 1つの部門(NULLの場合は0)
1対1(あまり使わない)
「1人の社員に1つの個人情報」
多対多(中間テーブルが必要)
「社員とプロジェクトの関係」— 1人の社員が複数のプロジェクトに参加し、1つのプロジェクトに複数の社員が参加する。
多対多の関係は、そのままではデータベースのテーブルで表現できない。
次のStepで 中間テーブル を使った解決方法を学ぶ。
Step 6: 多対多の解決
中間テーブルの導入
多対多の関係は、 中間テーブル を挟んで 2つの1対多 に分解する。
変換前:多対多
変換後:中間テーブルで2つの1対多に
中間テーブルのポイント
- 主キー は両方のエンティティの主キーの 複合主キー にする
- 中間テーブルには 追加の属性 を持たせることもある(役割、配属日など)
- 外部キーで両方のテーブルを参照する
-- 多対多を中間テーブルで解決
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL
);
CREATE TABLE projects (
project_id INTEGER PRIMARY KEY,
project_name VARCHAR(100) NOT NULL
);
-- 中間テーブル(多対多を2つの1対多に分解)
CREATE TABLE assignments (
emp_id INTEGER REFERENCES employees(emp_id),
project_id INTEGER REFERENCES projects(project_id),
role VARCHAR(50),
assigned_date DATE,
PRIMARY KEY (emp_id, project_id)
);
INSERT INTO employees VALUES (1, '田中太郎');
INSERT INTO employees VALUES (2, '佐藤花子');
INSERT INTO employees VALUES (3, '鈴木一郎');
INSERT INTO projects VALUES (1, 'ECサイト開発');
INSERT INTO projects VALUES (2, '社内システム改修');
INSERT INTO assignments VALUES (1, 1, 'リーダー', '2024-01-01');
INSERT INTO assignments VALUES (2, 1, 'メンバー', '2024-01-01');
INSERT INTO assignments VALUES (2, 2, 'リーダー', '2024-04-01');
INSERT INTO assignments VALUES (3, 1, 'メンバー', '2024-02-01');
-- 社員とプロジェクトの関係を表示
SELECT e.emp_name, p.project_name, a.role
FROM assignments a
INNER JOIN employees e ON a.emp_id = e.emp_id
INNER JOIN projects p ON a.project_id = p.project_id
ORDER BY p.project_name, a.role;
「AはBに複数対応し、BもAに複数対応する」関係を見つけたら多対多である。
- 社員とプロジェクト:1人が複数プロジェクト、1プロジェクトに複数社員 → 多対多
- 学生と授業:1学生が複数授業、1授業に複数学生 → 多対多
- 商品とカテゴリ:1商品が複数カテゴリ、1カテゴリに複数商品 → 多対多
Step 7: ER図からSQLへ
ER図をCREATE TABLE文に変換する
ER図の各要素は、以下のようにSQLに対応する。
| ER図の要素 | SQLの対応 |
|---|
| エンティティ | CREATE TABLE文 |
| 属性 | 列(カラム)の定義 |
| 主キー(PK) | PRIMARY KEY |
| 外部キー(FK) | REFERENCES(外部キー制約) |
| 1対多のリレーションシップ | 「多」側のテーブルに外部キー列を追加 |
| 多対多のリレーションシップ | 中間テーブルを作成 |
変換手順
以下のER図をSQLに変換してみよう。
手順1: エンティティ → テーブル(外部キーを持たないテーブルから作成)
手順2: 属性 → 列定義(PK、データ型、NOT NULLなどの制約)
手順3: リレーションシップ → 外部キー制約
-- ER図からSQLへの変換
-- 手順1:外部キーを持たないテーブルから作成
CREATE TABLE departments (
dept_id INTEGER PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(50)
);
-- 手順2:外部キーを持つテーブル(参照先が先に存在する必要がある)
CREATE TABLE employees (
emp_id INTEGER PRIMARY KEY,
emp_name VARCHAR(50) NOT NULL,
dept_id INTEGER REFERENCES departments(dept_id),
hire_date DATE NOT NULL,
salary INTEGER CHECK (salary > 0)
);
CREATE TABLE projects (
project_id INTEGER PRIMARY KEY,
project_name VARCHAR(100) NOT NULL,
start_date DATE
);
-- 手順3:中間テーブル(多対多のリレーションシップ)
CREATE TABLE assignments (
emp_id INTEGER REFERENCES employees(emp_id),
project_id INTEGER REFERENCES projects(project_id),
role VARCHAR(50),
PRIMARY KEY (emp_id, project_id)
);
-- データ投入
INSERT INTO departments VALUES (1, '営業部', '東京');
INSERT INTO departments VALUES (2, '開発部', '大阪');
INSERT INTO employees VALUES (1, '田中太郎', 1, '2020-04-01', 350000);
INSERT INTO employees VALUES (2, '佐藤花子', 2, '2021-04-01', 400000);
INSERT INTO employees VALUES (3, '鈴木一郎', 2, '2022-04-01', 320000);
INSERT INTO projects VALUES (1, 'ECサイト開発', '2024-01-01');
INSERT INTO projects VALUES (2, '社内システム改修', '2024-04-01');
INSERT INTO assignments VALUES (1, 1, 'リーダー');
INSERT INTO assignments VALUES (2, 1, 'メンバー');
INSERT INTO assignments VALUES (2, 2, 'リーダー');
INSERT INTO assignments VALUES (3, 1, 'メンバー');
-- 全テーブルを結合して確認
SELECT e.emp_name, d.dept_name, p.project_name, a.role
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
INNER JOIN assignments a ON e.emp_id = a.emp_id
INNER JOIN projects p ON a.project_id = p.project_id
ORDER BY e.emp_name;
外部キー制約がある場合、 参照先のテーブルを先に作成する 必要がある。
上の例では departments → employees → projects → assignments の順序で作成している。
削除する際は逆順(assignments → employees → departments)で行う。
Step 8: 実践課題
課題1:ECサイトのER図を読み取ろう
以下のER図を読み取り、各テーブルの役割とリレーションシップを説明せよ。
確認ポイント:
- 顧客と注文の関係は?(1対多 or 多対多?)
- 注文と商品の関係は? 中間テーブルはどれ?
- 商品とカテゴリの関係は? なぜ中間テーブルが必要?
課題2:ER図からCREATE TABLE文を書こう
課題1のER図をもとに、CREATE TABLE文を書いてみよう。
-- 課題2:ECサイトのER図からCREATE TABLE文を作成
-- ヒント:外部キーを持たないテーブルから作成する
-- 1. categories
-- 2. customers
-- 3. products
-- 4. orders(customersを参照)
-- 5. order_details(orders, productsを参照)
-- 6. product_categories(products, categoriesを参照)
-- ここにCREATE TABLE文を書こう
-- テストデータの投入例
-- INSERT INTO categories VALUES (1, '電子機器');
-- INSERT INTO categories VALUES (2, 'アクセサリ');
-- INSERT INTO customers VALUES (1, '山田太郎', 'yamada@example.com', '東京都');
-- INSERT INTO products VALUES (1, 'ノートPC', 80000, 50);
-- INSERT INTO products VALUES (2, 'マウス', 3000, 200);
SELECT 'ここにCREATE TABLE文を書いてみよう' AS message;
課題3:要件からER図を考えよう
以下の要件から、ER図(テーブル構成)を考えよう。
図書館管理システムの要件:
- 図書を管理する(タイトル、著者名、出版年、ISBN)
- 会員を管理する(名前、住所、電話番号)
- 会員は図書を借りることができる(貸出日、返却予定日、実際の返却日)
- 1冊の図書を複数の会員が借りられる(時期が異なれば可)
- 1人の会員は複数冊の図書を同時に借りられる
考えるべきポイント:
- エンティティは何か?(名詞を抽出)
- 図書と会員の関係は?(1対多?多対多?)
- 中間テーブルは必要か?
まとめ
この章では、 ER図とデータベース設計 について学んだ。
🎯 達成できたこと
- ✅ ER図の必要性を説明できる
- ✅ エンティティ、属性、リレーションシップを識別できる
- ✅ カーディナリティ(1対多、多対多)を説明できる
- ✅ 多対多を中間テーブルで解決できる
- ✅ ER図からCREATE TABLE文を書ける
- ✅ 要件からER図を作成できる
📚 学んだ内容
- ER図はデータベース設計の共通言語であり、チームでの認識共有に不可欠
- エンティティ(テーブル)、属性(列)、リレーションシップ(外部キー)が基本要素
- カーディナリティで「数の関係」を表す(1対1、1対多、多対多)
- 多対多は中間テーブルを導入して2つの1対多に分解する
- ER図からCREATE TABLE文を機械的に変換できる
- テーブル作成の順序は外部キーの参照先を先にする
🚀 次のステップ
これでデータベースの基礎学習は完了である。
ここで学んだSQLとデータベース設計の知識は、Spring教材のMyBatis(Day 10)でJavaアプリケーションからデータベースにアクセスする際に活かされる。
💡 よくある質問
Q1: ER図のツールは何を使えばいい?
A: 初学者には draw.io が直感的で使いやすい。チーム開発では Mermaid がGitHubとの相性が良い(テキストで管理できるため差分が見やすい)。実務では MySQL Workbench や A5:SQL Mk-2 で既存のDBからER図を自動生成することも多い。
Q2: ER図のIE記法とChen記法の違いは?
A: IE記法(Crow's foot記法)はリレーションシップを線の端の記号で表し、実務で広く使われている。Chen記法はリレーションシップをひし形で表す、学術的な記法である。本教材ではIE記法に統一している。
Q3: 多対多はいつも中間テーブルが必要?
A: はい。リレーショナルデータベースでは、多対多の関係を直接テーブルで表現できないため、必ず中間テーブルが必要になる。中間テーブルには結合するだけの最小限の列(両方の主キー)に加えて、関係に付随する属性(役割、日付など)を持たせることもできる。
Q4: AIにER図を描かせてもいい?
A: AIはER図の作成が得意である。「〇〇システムのER図をMermaid記法で描いて」と依頼すると、適切なER図を提案してくれる。ただし、以下のポイントは人間がレビューする必要がある。
- ビジネス要件が正しく反映されているか
- カーディナリティ(1対多 or 多対多)が正しいか
- 中間テーブルに必要な属性が含まれているか
Q5: 実務ではER図をどのタイミングで描く?
A: 通常は 要件定義 または 基本設計 のフェーズでER図を作成する。先にER図を描いてからCREATE TABLE文を作成する流れが一般的である。開発が進む中でER図を更新していくことも重要で、ER図とデータベースの実態がずれないように管理する。
練習問題
この章の内容を理解できたか確認しよう。
ER図を使う主な目的として正しいものを選べ。
正解
B. データベースの構造を視覚的に表現し、設計の共通認識を持つため
解説
ER図(Entity Relationship Diagram:実体関連図)はデータベースのテーブル構造と
テーブル間の関係を視覚的に表現する設計図である。
ER図の役割:
- 設計者・開発者・顧客の間でデータ構造の共通認識を持つ
- SQL文を書く前にテーブル設計を確認・議論できる
- リレーションシップ(1対多、多対多)を直感的に把握できる
ER図の主な要素:
- エンティティ: テーブルに対応する「モノ」(長方形で表現)
- 属性: テーブルの列(エンティティ内に記述)
- リレーションシップ: テーブル間の関係(線で表現)
- カーディナリティ: 関係の多重度(1対1、1対多、多対多)
Mermaid記法(本サイトで使用):
departments ||--o{ employees : "所属"
|| = ちょうど1
o{ = 0以上(多数)
以下のER図を見て、エンティティ(テーブルに対応する「モノ」)として正しいものを選べ。
解説
エンティティはER図において「モノ」の概念を表し、テーブルに対応する。
エンティティ vs 属性:
- エンティティ: 管理したいモノや概念(テーブル名)→ 図の長方形ボックス全体
- 例:
employees(社員)、departments(部門)、projects(プロジェクト)
- 属性: エンティティが持つ情報(列名)→ ボックス内に列挙されている項目
- 例:
emp_id、emp_name、dept_id
emp_id や emp_name は employees エンティティの 属性(列)であり、
エンティティそのものではない。dept_id も同様に属性の一つである。
以下のER図を参照し、employees エンティティの属性(列に対応する情報)として正しいものを選べ。
解説
属性はエンティティが持つ情報であり、テーブルの列に対応する。
属性 vs エンティティ:
emp_name(社員名): employees エンティティの 属性(列名)← 正解
departments: 別のエンティティ(テーブル)
assignments: 別のエンティティ(中間テーブル)
- 関係線: リレーションシップを表すもの(属性でもエンティティでもない)
employees エンティティの属性例:
emp_id(社員ID): 主キー
emp_name(社員名): 必須
dept_id(部門ID): 外部キー
hire_date(入社日)
salary(給与)
email(メールアドレス): UNIQUE
ER図での属性の表し方:
属性はエンティティの長方形の中に列名として記述される。
Mermaid ER図では { INTEGER emp_id PK } のような形式で記述する。
以下のER図が表す意味として正しいものを選べ。
記号の左側(||)と右側(o{)がそれぞれ何を意味するか読み解こう
正解
C. 社員は部門に所属しなくてもよく、1つの部門に複数の社員が所属できる
解説
Mermaid ER図の記法では以下のシンボルでカーディナリティを表す。
カーディナリティ記号(Mermaid):
departments ||--o{ employees : "所属" の解読:
- 左側
||(departments側): 1つの部門(必須)
- 右側
o{(employees側): 0以上の社員(任意・多数)
- つまり「1つの部門に0以上の社員が所属できる(社員がいない部門もあり得る)」
選択肢との対応:
- C が正解: 「所属しなくてもよく(o=0以上)、複数の社員が所属できる({=多数)」
- D は間違い:
o{ は0以上なので、社員がいない部門も許容される
以下のER図において、employees(社員)と projects(プロジェクト)の関係のカーディナリティを選べ。
解説
「1人の社員が複数のプロジェクトに参加でき、1つのプロジェクトには複数の社員が参加できる」関係は 多対多 である。
カーディナリティの種類:
| 種類 | 例 |
|---|
| 1対1 | 社員と社員証(1人に1枚) |
| 1対多 | 部門と社員(1部門に複数社員) |
| 多対多 | 社員とプロジェクト(社員も複数プロジェクト、プロジェクトも複数社員) |
多対多の特徴:
- 「社員からみてもプロジェクトが多数」かつ「プロジェクトからみても社員が多数」
- RDBでは直接表現できないため、中間テーブルで2つの1対多に分解する
- サンプルDBでは
assignments(emp_id, project_id) が中間テーブル
Mermaid記法:
employees }o--o{ projects : "アサイン"
以下のER図は、社員(employees)とプロジェクト(projects)の多対多関係を実装したものである。
多対多のリレーションシップをRDBで実装する方法として正しいものを選べ。
正解
B. 中間テーブル(関連テーブル)を作成し、両テーブルのIDを外部キーとして持たせる
解説
リレーショナルデータベースでは多対多を直接表現できないため、
中間テーブル(関連テーブル、ジャンクションテーブル)を使って
2つの1対多に分解する。
サンプルDBでの実装例:
employees(1) ---< assignments >--- (1)projects
(多対多の中間)
assignments テーブル:
emp_id → employees への外部キー(1対多の「多」側)
project_id → projects への外部キー(1対多の「多」側)
PRIMARY KEY(emp_id, project_id) → 同じ組み合わせの重複を防ぐ
role → 関係そのものの属性(このアサインメントでの役割)
中間テーブルの特徴:
- 両エンティティのIDを外部キーとして持つ
- (ID1, ID2) の複合主キーで重複を防ぐ
- 関係に関する追加情報(属性)を持てる(例: role, 参加日時)
- テーブル名・カラム名は 小文字 で入力する(例:
employees, dept_id)
- SQLキーワードは 大文字 で入力する(例:
SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
以下のER図を参照し、assignments テーブルを作成するCREATE TABLE文を完成させよ。
(emp_id と project_id が複合主キー、それぞれ外部キー)
CREATE TABLE assignments (
emp_id INTEGER
employees(emp_id),
project_id INTEGER REFERENCES projects(project_id),
role VARCHAR(50),
KEY (emp_id, project_id)
);
外部キーは REFERENCES、複合主キーは PRIMARY KEY (col1, col2) で指定する
解答例
CREATE TABLE assignments (emp_id INTEGER REFERENCES employees(emp_id), project_id INTEGER REFERENCES projects(project_id), role VARCHAR(50), PRIMARY KEY (emp_id, project_id));
解説
ER図のエンティティとリレーションシップからCREATE TABLE文を作成するステップ:
- エンティティ → テーブル名
- 属性 → 列名・データ型
- 主キー →
PRIMARY KEY
- 外部キー(他エンティティへの参照) →
REFERENCES
- 多対多の中間テーブル → 複合主キー
PRIMARY KEY (列1, 列2)
REFERENCES の書き方:
列名 データ型 REFERENCES 参照先テーブル名(参照先列名)
複合主キーの書き方:
PRIMARY KEY (列1, 列2)
-- CREATE TABLE の最後に記述する
複合主キーを使うことで、同じ社員とプロジェクトの組み合わせが
重複して登録されることを防ぐことができる。
- テーブル名・カラム名は 小文字 で入力する(例:
employees, dept_id)
- SQLキーワードは 大文字 で入力する(例:
SELECT, FROM, WHERE)
正しい例: SELECT emp_name FROM employees WHERE dept_id = 1;
以下のER図を参照し、enrollments(中間テーブル)を作成するCREATE TABLE文を完成させよ。
「学生(students)と授業(courses)の多対多関係を管理する中間テーブル enrollments を設計せよ」
という要件で、以下のCREATE TABLE文を完成させよ。
CREATE TABLE enrollments (
student_id INTEGER
students(student_id),
course_id INTEGER
courses(course_id),
enrolled_at DATE,
KEY (student_id, course_id)
);
多対多の中間テーブルは assignments テーブルと同じパターンで設計する
解答例
CREATE TABLE enrollments (student_id INTEGER REFERENCES students(student_id), course_id INTEGER REFERENCES courses(course_id), enrolled_at DATE, PRIMARY KEY (student_id, course_id));
解説
多対多の中間テーブル設計は assignments テーブルと同じパターンである。
設計パターン(多対多の解決):
- 多対多の関係を確認する(学生 ←多対多→ 授業)
- 中間テーブルを作成する(
enrollments)
- 両エンティティのIDを外部キーとして持たせる
- 複合主キーで重複を防ぐ
enrollments テーブルの設計:
student_id: students.student_id への外部キー
course_id: courses.course_id への外部キー
enrolled_at: 関係の属性(登録日)
PRIMARY KEY(student_id, course_id): 同じ学生が同じ授業に重複登録されることを防ぐ
このパターンを覚えれば:
社員とプロジェクト、学生と授業、ユーザーとタグなど
あらゆる多対多の関係に応用できる。