メインコンテンツまでスキップ

第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 図が書けます (本ガイドも全章これを使用)。

記号意味
PKPrimary Key (主キー)
FKForeign Key (外部キー)
UKUnique Key (一意制約)

リレーションシップとカーディナリティ

リレーションシップは、エンティティ間の「関係の多重度」を表します。

mermaid の erDiagram では、2 つのエンティティ間のリレーションシップを次のように書きます:

CUSTOMER ||--o{ ORDER : places

これは「CUSTOMER は ORDER を 0 個以上持つ (1 対多)」を意味し、関係名 (places) は動詞で書きます。

1 対 1

「人とパスポート」のような関係です (1 人 1 パスポート、1 パスポート 1 人)。

PASSPORT.person_idUK (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 WorkbenchMySQL 専用・フォワード / リバースエンジニアリング無料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 を参照。

ベストプラクティス

Jr 向けのコツ
  • 手書きから始める: 紙とペンで主要エンティティと関係を書き出してから、ツールで清書
  • 業務担当者と一緒に作る: 一人で完璧を目指さず、現場の人に「こう理解したけど合ってる?」と確認しながら
  • 正解は 1 つではない: 同じ業務でも、設計者の判断によって複数の E-R 図がありえる。チームで合意することが重要

演習

演習 1: 簡単な E-R 図を起こす

次の業務要件から E-R 図を作成してください。エンティティ・属性・カーディナリティを mermaid 記法で書いてみましょう。

  • ブログサイトでは、ユーザーが記事を投稿できる
  • 1 人のユーザーが複数の記事を投稿できる
  • 1 つの記事には複数のタグを付けられる
  • 1 つのタグは複数の記事で使われる
  • 各記事に他のユーザーがコメントできる (1 記事複数コメント)
  • コメントは記事と紐づき、書いたユーザーも紐づく
解答例

ポイント:

  • USER → POST は 1 対多 (1 ユーザーが複数の記事)
  • POST ↔ TAG は多対多 → 中間テーブル POST_TAG
  • COMMENTPOSTUSER の両方を参照 (1 対多 × 2)

ありがちな間違い:

  1. タグを POST.tags というカラムに CSV で入れる: 正規化に反する (第 1 正規形違反)。検索・集計が困難になる
  2. COMMENT.user_id を忘れる: 「誰がコメントしたか」が分からない
  3. COMMENT を自己参照 (返信機能) にする: 上の要件には「返信」がないので不要。要件にないものを追加しない

別解: 「タグの使用回数」を高速に取りたいなら、TAGusage_count カラムを追加する選択肢があります (非正規化)。ただし更新時の整合性管理が必要になるため、最初は集計クエリで対応するのが安全です (第 14 章 多対多 で議論)。

演習 2: カーディナリティ判定

次の関係はそれぞれ「1 対 1」「1 対多」「多対多」のどれでしょうか?

  1. ユーザーとプロフィール (1 ユーザーは 1 プロフィールを持つ)
  2. ブログ記事といいね (1 記事に複数のいいね、いいねは 1 つの記事につく)
  3. レシピと材料 (1 レシピに複数の材料、1 材料は複数のレシピで使われる)
  4. 注文と配送 (1 注文に対し配送は 1 回、配送伝票は 1 つの注文に対応)
  5. プレイリストと曲 (1 プレイリストに複数の曲、1 曲は複数のプレイリストに含まれる)
解答例
番号関係理由
1. ユーザーとプロフィール1 対 11 ユーザー → 1 プロフィール
2. 記事といいね1 対多1 記事 → 複数いいね、1 いいね → 1 記事
3. レシピと材料多対多1 レシピに複数材料 & 1 材料が複数レシピで使われる → 中間テーブル recipe_ingredients
4. 注文と配送1 対 11 注文 → 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 図 → テーブル定義の一気通貫の実践を扱います。