第12章 E-R 図の作成方法 — 業務要件を視覚化する
この章で学ぶこと
- E-R 図の基本要素 (エンティティ / 属性 / リレーションシップ) を説明できる
- カーディナリティ (1 対 1 / 1 対多 / 多対多) を mermaid 記法で書ける
- 業務要件 (例: 図書館) から E-R 図を起こす手順を踏める
- 主要な E-R 図ツール (mermaid / draw.io / PlantUML) の使い分けを知っている
第 10 章 キー概念 と 第 11 章 正規化 を理解していること。
E-R 図とは
E-R 図 (Entity-Relationship Diagram) は、データベースの構造をエンティティ (実体) と リレーションシップ (関係) の組み合わせで視覚的に表す図です。1976 年に Peter Chen によって提唱されました。
| 要素 | 例 |
|---|---|
| エンティティ | 顧客・商品・注文・社員・部署 |
| 属性 | 顧客名・商品価格・注文日時 |
| リレーションシップ | 「顧客が注文する」「商品が注文に含まれる」 |
エンティティの記法
mermaid の erDiagram 記法を使うと、テキストで E-R 図が書けます (本ガイドも全章これを使用)。
| 記号 | 意味 |
|---|---|
PK | Primary Key (主キー) |
FK | Foreign Key (外部キー) |
UK | Unique Key (一意制約) |
リレーションシップとカーディナリティ
リレーションシップは、エンティティ間の「関係の多重度」を表します。
mermaid の erDiagram では、2 つのエンティティ間のリレーションシップを次のように書きます:
CUSTOMER ||--o{ ORDER : places
これは「CUSTOMER は ORDER を 0 個以上持つ (1 対多)」を意味し、関係名 (places) は動詞で書きます。
1 対 1
「人とパスポート」のような関係です (1 人 1 パスポート、1 パスポート 1 人)。
PASSPORT.person_id を UK (UNIQUE 制約) で守ることで「1 人 1 パスポート」を保証します。
1 対多
「部署と社員」のような関係です (1 部署に複数社員、1 社員は 1 部署所属)。
外部キー EMPLOYEE.dept_id を UNIQUE にしなければ、複数社員が同じ部署を参照できます (= 1 対多)。
多対多
「学生と授業」のような関係です (1 学生が複数授業を履修、1 授業に複数学生が履修)。
多対多は中間テーブル (上の例なら ENROLLMENT) で表現します。中間テーブル自身に属性 (履修日 / 成績) を持たせられるのが利点です。多対多の詳細は第 14 章 多対多で扱います。
mermaid では }o--o{ のような「直接の多対多」記法も書けますが、RDB では必ず中間テーブルで実装します。物理設計レベルの E-R 図では、中間テーブルを明示するほうが正確で誤解が少なくなります。
実践例: EC サイトの E-R 図
E-R 図の典型例として、EC サイトを見てみましょう。
線の向きと記号を読み解くと:
- 1 人の顧客が複数の注文を出す (
CUSTOMER ||--o{ ORDER) - 1 つの注文に複数の注文明細がある (
ORDER ||--o{ ORDER_ITEM) - 1 つの商品は複数の注文明細に含まれる (
PRODUCT ||--o{ ORDER_ITEM) - カテゴリは自己参照 (親カテゴリ ID) で階層を表現
E-R 図を作成する手順
業務要件から E-R 図を起こす標準的な手順は次の通りです。
Step 1: エンティティを抽出する
業務要件の文章を読みながら、名詞に注目します。永続化が必要なモノ・人・出来事がエンティティ候補です。
Step 2: 属性を洗い出す
各エンティティに必要な属性を列挙します。「これは将来検索 / 表示 / 集計するか?」を基準に判断します。
顧客 (CUSTOMER) の属性候補:
- 識別子: customer_id (PK)
- 基本情報: name (必須), email (必須・一意), phone
- 認証情報: password_hash (必須)
- メタ: created_at, updated_at, is_active
Step 3: リレーションシップを定義する
エンティティ間の関係を「1 対 1 / 1 対多 / 多対多」に分類します。
Step 4: 正規化を確認する
第 11 章 正規化 のチェック (第 1 〜 第 3 正規形) を行い、必要なら分解します。
Step 5: 物理設計に進む
E-R 図を CREATE TABLE 文に展開し、データ型・インデックス・制約を決めます (詳しくは第 9 章 設計の流れの物理設計参照)。
スーパータイプとサブタイプ — 継承関係の表現
「ユーザーは顧客でもあるし、社員でもある」のような継承関係を表す手法です。
この設計では users テーブルに共通属性を置き、customers / employees のサブタイプテーブルで固有属性を追加します。USER を中心に複数のサブタイプを実装するパターンは、認証認可システムの設計でも頻出します (第 15 章 認証認可で扱います)。
実践例: 図書館管理システム
複合的な題材で E-R 図を起こしてみます。
業務要件
- 会員は本を借りられる
- 1 冊の本に複数の著者がいる場合がある
- 本にはカテゴリがある (階層構造)
- 会員は本を予約できる (貸出中の場合)
- 貸出には返却期限と延滞料金がある
E-R 図
ポイント:
BOOK_AUTHORは本と著者の多対多を表現する中間テーブルCATEGORY.parent_category_idで自己参照 (階層構造)LOAN(貸出) は「会員が本を借りる」イベントを表すエンティティRESERVATION(予約) は「会員が本を予約する」イベント
E-R 図作成ツール
| ツール | 特徴 | 価格 | 本ガイドでの使用 |
|---|---|---|---|
| mermaid | テキストベース・Git 管理可能・Markdown に埋め込める | 無料 | ◯ (本ガイドの図はすべて mermaid) |
| draw.io (app.diagrams.net) | GUI・Web 版あり・無料 | 無料 | 描画優先のときに推奨 |
| PlantUML | テキストベース・バージョン管理可能 | 無料 | 大規模図の描画に向く |
| MySQL Workbench | MySQL 専用・フォワード / リバースエンジニアリング | 無料 | MySQL 採用時に便利 |
| Lucidchart | 高機能・チーム作業対応 | 有料 | 商用プロジェクトのドキュメント化 |
PlantUML 記法 (参考)
@startuml
entity "Customer" {
* customer_id : int <<PK>>
--
* email : varchar(255) <<UK>>
* name : varchar(100)
created_at : timestamp
}
entity "Order" {
* order_id : int <<PK>>
--
* customer_id : int <<FK>>
* order_date : datetime
total_amount : decimal(12,2)
}
Customer ||--o{ Order : places
@enduml
PlantUML 公式は https://plantuml.com/ja/ie-diagram を参照。
ベストプラクティス
- 手書きから始める: 紙とペンで主要エンティティと関係を書き出してから、ツールで清書
- 業務担当者と一緒に作る: 一人で完璧を目指さず、現場の人に「こう理解したけど合ってる?」と確認しながら
- 正解は 1 つではない: 同じ業務でも、設計者の判断によって複数の E-R 図がありえる。チームで合意することが重要
演習
次の業務要件から E-R 図を作成してください。エンティティ・属性・カーディナリティを mermaid 記法で書いてみましょう。
- ブログサイトでは、ユーザーが記事を投稿できる
- 1 人のユーザーが複数の記事を投稿できる
- 1 つの記事には複数のタグを付けられる
- 1 つのタグは複数の記事で使われる
- 各記事に他のユーザーがコメントできる (1 記事複数コメント)
- コメントは記事と紐づき、書いたユーザーも紐づく
解答例
ポイント:
USER → POSTは 1 対多 (1 ユーザーが複数の記事)POST ↔ TAGは多対多 → 中間テーブルPOST_TAGCOMMENTはPOSTとUSERの両方を参照 (1 対多 × 2)
ありがちな間違い:
- タグを
POST.tagsというカラムに CSV で入れる: 正規化に反する (第 1 正規形違反)。検索・集計が困難になる COMMENT.user_idを忘れる: 「誰がコメントしたか」が分からないCOMMENTを自己参照 (返信機能) にする: 上の要件には「返信」がないので不要。要件にないものを追加しない
別解: 「タグの使用回数」を高速に取りたいなら、TAG に usage_count カラムを追加する選択肢があります (非正規化)。ただし更新時の整合性管理が必要になるため、最初は集計クエリで対応するのが安全です (第 14 章 多対多 で議論)。
次の関係はそれぞれ「1 対 1」「1 対多」「多対多」のどれでしょうか?
- ユーザーとプロフィール (1 ユーザーは 1 プロフィールを持つ)
- ブログ記事といいね (1 記事に複数のいいね、いいねは 1 つの記事につく)
- レシピと材料 (1 レシピに複数の材料、1 材料は複数のレシピで使われる)
- 注文と配送 (1 注文に対し配送は 1 回、配送伝票は 1 つの注文に対応)
- プレイリストと曲 (1 プレイリストに複数の曲、1 曲は複数のプレイリストに含まれる)
解答例
| 番号 | 関係 | 理由 |
|---|---|---|
| 1. ユーザーとプロフィール | 1 対 1 | 1 ユーザー → 1 プロフィール |
| 2. 記事といいね | 1 対多 | 1 記事 → 複数いいね、1 いいね → 1 記事 |
| 3. レシピと材料 | 多対多 | 1 レシピに複数材料 & 1 材料が複数レシピで使われる → 中間テーブル recipe_ingredients |
| 4. 注文と配送 | 1 対 1 | 1 注文 → 1 配送 |
| 5. プレイリストと曲 | 多対多 | 1 プレイリストに複数曲 & 1 曲が複数プレイリストに → 中間テーブル playlist_songs |
補足 (1 対 1 の設計): 1 対 1 の関係は「同じテーブルに統合できないか?」を最初に検討します (例: ユーザーとプロフィールは users テーブル 1 つにまとめてしまうことが多い)。あえて分けるのは:
- プロフィール情報が肥大で頻繁にアクセスしない (パフォーマンス目的の縦分割)
- アクセス権限を分けたい (基本情報は誰でも、機微情報は本人だけ)
のような明確な理由があるときです。
ありがちな間違い: 5 のプレイリストと曲を「1 対多」と判定すること。「1 曲は複数プレイリストに含まれる」点を見落としやすい。「双方向で複数あり得るか」を確認するのがコツ。
まとめ
この章で学んだことを整理します。
- E-R 図はエンティティ・属性・リレーションシップでデータベース構造を視覚化する
- カーディナリティは 1 対 1 / 1 対多 / 多対多 の 3 種類が基本
- 多対多は中間テーブルで実装する
- 作成手順は「エンティティ抽出 → 属性洗い出し → 関係定義 → 正規化確認 → 物理設計」
- ツールは mermaid (Git 管理向き) / draw.io (描画優先) / PlantUML (大規模) / Workbench (MySQL 専用) を使い分け
次章では、ここまでの設計手法を組み合わせて、要件 → E-R 図 → テーブル定義の一気通貫の実践を扱います。