🎓 レベル:標準 | 重要度:A(必須)
📎 前提:リレーショナルモデルと正規化 | 関連:スタースキーマと次元モデリング
要点(BLUF)
- ER図(Entity-Relationship Diagram)は、データをエンティティ(モノ・コト)・属性・**関係(リレーションシップ)**で描く設計図。テーブル化の前の“設計の言語”。
- 関係にはカーディナリティ(多重度)がある:1対1・1対多・多対多。設計の山場は多対多で、これは中間(連関)テーブルに分解するのが定石。
- 設計は 概念モデル(何を持つか)→ 論理モデル(テーブル・キー)→ 物理モデル(型・インデックス) と段階を踏む。早い段階で関係の多重度を間違えると後で全部やり直しになる。
概念 ── エンティティと関係
エンティティは「顧客」「注文」「商品」のような独立して存在するモノ/コト。属性はその性質(顧客の名前・住所)。関係は「顧客が注文する」「注文が商品を含む」といったエンティティ同士の繋がりです。
要するにER図は、業務の言葉(顧客・注文・商品)を、そのままテーブルとキーに翻訳する前の中間表現です。ここで構造を固めてから物理設計に落とします。
仕組み ── カーディナリティと多対多の分解
erDiagram
CUSTOMER ||--o{ ORDER : "発注する"
ORDER ||--|{ ORDER_ITEM : "含む"
PRODUCT ||--o{ ORDER_ITEM : "に現れる"
CUSTOMER {
int cust_id PK
text name
}
ORDER {
int order_id PK
int cust_id FK
text ordered_at
}
PRODUCT {
int product_id PK
text name
int price
}
ORDER_ITEM {
int order_id FK
int product_id FK
int quantity
}
ポイントは 注文と商品が「多対多」であること(1注文に複数商品、1商品は複数注文に現れる)。リレーショナルDBは多対多を直接持てないので、ORDER_ITEM(連関テーブル)を挟んで「1対多 × 多対1」に分解します。ORDER_ITEM は両側の外部キーを持ち、数量などの関係そのものの属性を載せます。
flowchart LR
A["多対多(注文 ↔ 商品)"] --> B["連関テーブル ORDER_ITEM で分解"]
B --> C["注文 1対多 ORDER_ITEM 多対1 商品"]
設計の勘所 ── 3段階で詰める
| 段階 | 決めること | 例 |
|---|---|---|
| 概念モデル | エンティティと関係(多重度) | 顧客・注文・商品とその繋がり |
| 論理モデル | テーブル・主キー・外部キー | customers, orders, order_item |
| 物理モデル | 列の型・インデックス・制約 | cust_id INTEGER PK, INDEX(cust_id) |
概念→論理→物理の順で、抽象から具体へ降りていきます。物理(インデックス等)は インデックスと実行計画 で扱います。
なぜそうするか ── 多重度を最初に固める
なぜER図を先に描くのか。関係の多重度を間違えると、テーブル構造ごと作り直しになるからです。「1顧客に住所は1つ」と思って住所を顧客テーブルに入れた後、「複数住所が必要」と判明すれば、列の分離・データ移行が発生します。図で多重度を関係者と合意してから物理に落とすと、この手戻りを防げます。連関テーブルへの分解も、図の段階で見抜けば自然に設計に入ります。
⚠️ よくある落とし穴
- 多対多をそのままにする → 片側に繰り返し列やカンマ区切り値を詰め込み、1NF違反&検索不能に。必ず連関テーブルへ。
- 関係の属性を置き忘れる → 「数量」「単価」は注文でも商品でもなく注文明細(関係)の属性。連関テーブルに載せる。
- 概念設計を飛ばして物理から作る → 後から多重度の誤りが露見し大規模な作り直しに。
対応ラボ
なし(設計回)。連関テーブルを使ったJOINの実演は SQLの基礎(結合・集約・サブクエリ) のラボで扱う。
関連
- テーブル分割の根拠(冗長排除)は リレーショナルモデルと正規化
- 分析用に関係を“あえて崩す”設計が スタースキーマと次元モデリング
- 物理段階のインデックス設計は インデックスと実行計画