論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
ER 図
Entity-Relationship Diagram
データベース設計を「実体(エンティティ)」と「関係(リレーションシップ)」で図式化する手法。
DB設計データモデリングERDChen記法IE記法

🔖 キーワード索引

この用語ページの主要トピックを一覧から飛べます。

📍 文脈💡 30秒結論🎨 直感📐 数式・定義🔬 数式の読み解き🧮 SSDSE-B-2026 計算🐍 Python 実装⚠️ 落とし穴🌐 関連手法🔗 関連用語📚 グループ教材🗺 概念マップ📜 歴史と系譜🔧 実装詳細⚙️ 運用とトラブル💴 コストと見積もり🛡 ガバナンスとセキュリティ🏭 産業事例📊 比較表📝 演習💥 失敗例📖 用語辞典📚 参考文献

💡 30秒で分かる結論

🍰 まずはやさしく

データの設計図のようなものです。

データベースの構造を整理するために使います。

スマホアプリのデータ管理などに役立ちます。

図を作るための3つの要素について学びます。

📍 あなたが今見ているもの — 文脈ボックス

🍰 まずはやさしく

データベースを作るための重要な道具です。

データの関係を絵にして整理するために使います。

部活の名簿などを効率よく作る時に便利です。

図の書き方や種類について詳しく読みます。

論文・業務文書で 「ER 図」「ER モデル」「Entity-Relationship Diagram」「ERD」「データモデル」「概念設計」「論理設計」 といった表現が出てきたら、 このページです。

ER 図はデータベース設計の 最重要ツール。 業務要件をヒアリングして、 「どんなデータが」「どう関係しているか」を絵にする。 これなしに DB を設計すると、 後で「テーブルが増えすぎて管理不能」になります。

用語の系譜:1976 年 Peter Chen が提唱。 リレーショナルモデル(Codd, 1970)と並ぶ、 データベース理論の二大柱。 80 年代に IE 記法(James Martin)、 90 年代に UML へと進化。

本ページでは ER 図の歴史、 記法の違い、 描き方、 正規化との関係、 ツール、 そして SSDSE データを RDB に格納する設計例まで網羅します。 NoSQL の文脈での進化(document、 graph データベース)にも触れます。

🎨 直感で掴む

🍰 まずはやさしく

組織図と家系図を合わせたようなものです。

データのつながりを一目で分かるようにします。

図書館で本を借りる仕組みなどを例に考えます。

パズルの設計図のように考える方法を読みます。

ER 図を 「組織図」と「家系図」の合体と例えると分かりやすい。 組織図は「箱」と「線」で組織構造を表す。 ER 図は「エンティティ(箱)」と「リレーションシップ(線)」でデータ構造を表す。

🎬 ストーリー:図書館システムを設計する

図書館の業務を IT 化する。 ヒアリングしたら:

これを ER 図にすると:

[会員] --借りる(0..*)-- [貸出記録] --(*..1)-- [本] --書いた(*..*)-- [著者]
                                              |
                                              -属する(*..1)- [ジャンル]
    

これだけ描けば、 「会員テーブル」「本テーブル」「貸出記録テーブル」「著者テーブル」「ジャンルテーブル」と、 多対多を解消する「著者本テーブル(関連テーブル)」が必要、 と一目で分かる。

🎨 視覚的比喩:「立体パズル」

ER 図は 立体パズルの設計図。 各エンティティはパーツ、 リレーションシップは「どう組み合わさるか」。 設計図なしに作ると、 後で「ピースが合わない」事態に。 描いてから組むのが鉄則。

🌐 ER 図が活きる 4 つの場面

  1. 新規 DB 設計:白紙からテーブル構造を考える。
  2. 既存 DB のリバースエンジニアリング:レガシーシステムの構造を可視化。
  3. ステークホルダー間のコミュニケーション:非エンジニアにも理解しやすい。
  4. ドキュメント:DB 構造の継続的な記録、 新人教育。

🔍 SSDSE-B-2026 を ER 図で表現してみる

SSDSE-B-2026 は 1 つの大きな CSV ですが、 これを RDB に格納するなら:

[Prefecture] --(1..*)-- [YearlyStat] --属する(*..1)-- [Category]
   |                       |
   都道府県名               年度
   地域コード              人口・出生数・etc.
    

この設計だと、 1 県あたり 1 行ではなく「県 × 年度」で複数行になり、 経年変化を見やすい形に正規化される。 ER 図がなければこの判断は出てこない。

🎨 概念図で押さえる

ER 図はエンティティ(実体)と関係(リレーションシップ)を視覚化する。 ここでは「カーディナリティ・3 種類のリレーション・正規化までの流れ」を概念図で確認する。

エンティティと属性の構造概念図
図 A. 1 つのエンティティ(テーブル)には主キー(🔑PK)と属性が並ぶ。 SSDSE-B-2026 では「都道府県コード」が主キー候補。
ER 図のカーディナリティ 1対1 1対多 多対多
図 B. カーディナリティ(多重度)の 3 パターン。 SSDSE-B「都道府県 1 — 多 市区町村」は典型的な 1:N。 M:N は中間テーブルへ分解する。
ER 図から正規化されたテーブル群への変換フロー
図 C. ER 図の 3 段階(概念 → 論理 → 物理)。 SSDSE-B のテーブル設計でも、 まず概念を整理し、 その後 PK/FK と型を確定する流れが効く。

🎨 R282 補強: ER 図の実装デモ

「ER 図 → 正規化 → CREATE TABLE → INSERT → 結合クエリ」までを SSDSE-B-2026 で一気通貫で示す。 ER 図は「絵」のままだと半分の理解しかない。

1. SQLite で DDL を発行

このコードでやること: 都道府県マスタ、 年度マスタ、 統計値テーブルを正規化して作成。 PK / FK 制約を全て明示する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import sqlite3

con = sqlite3.connect(':memory:')
con.executescript("""
CREATE TABLE pref (
  pref_code TEXT PRIMARY KEY,
  pref_name TEXT NOT NULL UNIQUE,
  region    TEXT
);
CREATE TABLE year (
  year INTEGER PRIMARY KEY
);
CREATE TABLE stat (
  pref_code TEXT NOT NULL,
  year      INTEGER NOT NULL,
  pop_total INTEGER,
  deaths    INTEGER,
  PRIMARY KEY (pref_code, year),
  FOREIGN KEY (pref_code) REFERENCES pref(pref_code),
  FOREIGN KEY (year)      REFERENCES year(year)
);
""")
print('テーブル作成完了')
for row in con.execute("SELECT name FROM sqlite_master WHERE type='table'"):
    print(' -', row[0])
📤 実行例(実測) テーブル作成完了 - pref - year - stat
テーブル作成完了 - pref - year - stat

💬 3 つのテーブルが ER 図通りに作成された。 PK 複合キー(pref_code, year)が stat に効く。

2. SSDSE-B-2026 から INSERT

このコードでやること: CSV を読み、 正規化された 3 テーブルに分割投入する。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A4200(死亡数) 北海道 5,092,000 75,120 東京都 14,086,000 137,241 沖縄県 1,468,000 15,110 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=0)
# 2 行目の日本語名の行を落とし、都道府県コードの行だけ残す
df = df[df['Code'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
# 都道府県コードは 'Code' 列。'SSDSE-B-2026' 列は年度
df = df.rename(columns={'Code': 'pref_code', 'Prefecture': 'pref_name'})
df['SSDSE-B-2026'] = pd.to_numeric(df['SSDSE-B-2026'], errors='coerce')
for _c in ['A1101', 'A4200']:
    df[_c] = pd.to_numeric(df[_c], errors='coerce')

# pref マスタ
pref = df[['pref_code', 'pref_name']].drop_duplicates()
pref['region'] = pref['pref_name'].map({'北海道':'北海道', '青森県':'東北'}).fillna('その他')
pref.to_sql('pref', con, if_exists='append', index=False)

# year マスタ
year = pd.DataFrame({'year': sorted(df['SSDSE-B-2026'].unique())})
year.to_sql('year', con, if_exists='append', index=False)

# stat 事実テーブル
stat = df[['pref_code', 'SSDSE-B-2026', 'A1101', 'A4200']].rename(
    columns={'SSDSE-B-2026':'year','A1101':'pop_total','A4200':'deaths'})
stat.to_sql('stat', con, if_exists='append', index=False)

print(f'pref: {con.execute("SELECT COUNT(*) FROM pref").fetchone()[0]} rows')
print(f'year: {con.execute("SELECT COUNT(*) FROM year").fetchone()[0]} rows')
print(f'stat: {con.execute("SELECT COUNT(*) FROM stat").fetchone()[0]} rows')
📤 実行例(実測) pref: 47 rows year: 12 rows stat: 564 rows
pref: 47 rows year: 12 rows stat: 564 rows

💬 47 都道府県 × 12 年度 = 564 行が事実テーブルに入り、 ER 図の関係が物理化された。

3. 結合クエリで ER 図の威力を確認

このコードでやること: pref と stat を JOIN し、 2023 年の死亡率 TOP5 を取得する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
q = """
SELECT p.pref_name,
       s.pop_total,
       s.deaths,
       ROUND(1000.0 * s.deaths / s.pop_total, 2) AS death_rate_permille
FROM stat s
JOIN pref p ON s.pref_code = p.pref_code
WHERE s.year = 2023
ORDER BY death_rate_permille DESC
LIMIT 5
"""
print(pd.read_sql(q, con))
📤 実行例(実測) pref_name pop_total deaths death_rate_permille 0 秋田県 914000 17517 19.17 1 青森県 1184000 20835 17.60 2 高知県 666000 11438 17.17 3 岩手県 1163000 19612 16.86 4 山形県 1026000 16975 16.54
pref_name pop_total deaths death_rate_permille 0 秋田 914000 17517 19.17 1 青森 1184000 20835 17.60 2 高知 666000 11438 17.17 3 岩手 1163000 19612 16.86 4 山形 1026000 16975 16.54

💬 FK で結合した結果、 「県名 + 統計値」が 1 行に揃う。 これが ER 図 → 正規化の核心。

4. ER 図の妥当性検証

このコードでやること: 参照整合性違反を意図的に発生させ、 FK 制約が効くことを確認。

1
2
3
4
5
6
con.execute('PRAGMA foreign_keys = ON')
try:
    con.execute("INSERT INTO stat VALUES ('R99999', 2023, 1000, 50)")
    print('NG: 制約違反が許された')
except sqlite3.IntegrityError as e:
    print(f'OK: 参照整合性違反を検知 → {e}')
📤 実行例(実測) OK: 参照整合性違反を検知 → FOREIGN KEY constraint failed
OK: 参照整合性違反を検知 → FOREIGN KEY constraint failed

💬 ER 図に基づく FK 制約が物理レイヤで正しく効いている。 これがあれば「存在しない県コード」が紛れ込まない。

正規形条件SSDSE での該当
第 1 正規形属性が原子値全列スカラー
第 2 正規形部分関数従属除去pref_name は pref に分離
第 3 正規形推移関数従属除去region は pref に集約

🎮 触って学ぶ:カーディナリティと連関テーブル

教材の定番例「学生・科目・成績」で、 リレーション「履修」の 多重度(カーディナリティ)1:1 / 1:N / N:M に切り替えると、 クロウフット(鳥の足, IE 記法)の記号と「意味」がどう変わるかを体感する。 実体(エンティティ)=長方形、 関連=線+多重度記号で描く。 N:M は直接テーブル化できないので、 ボタンで 連関(中間)テーブル「履修」へ分解できる。 主キー(PK)・外部キー(FK)のハイライトで対応を確認しよう。

多重度:
記号の読み方(IE / クロウフット記法):短い縦棒 =「1」、 三又の鳥の足 < =「多」。 鳥の足は「多」の側のエンティティに付く。 実体をタップ/クリックすると、 そのテーブルの PK・FK を強調表示します。

📐 数式または定義

🍰 まずはやさしく

図を描くための共通のルールです。

誰が見ても同じ意味に伝わるように使います。

買い物サイトの注文データなどを整理する時に使います。

図で使う記号や線の意味について読みます。

ER 図には「数式」よりも「記法の規則」があります。 主要記法を整理。

1. Chen 記法(オリジナル、 1976)

2. IE 記法(クロウフット、 現代主流)

3. 多重度(カーディナリティ)の表記

関係ChenIE (クロウフット)UML
1 対 11:1│ ── │1..1
1 対 多1:N│ ── Ϟ1..*
多対多M:NϞ ── Ϟ*..*
0 または 10..1○│0..1
1 以上1..N│Ϟ1..*
0 以上0..N○Ϟ0..*

4. 主キーと外部キー

5. 弱エンティティ

親エンティティに依存し、 単独では存在できない。 二重線の四角で表記。 例:「貸出記録」は「会員」と「本」がないと存在しない(が、 これは関連テーブルで表現するのが現代的)。

6. 多重度の決定式

2 つのエンティティ A, B の関係多重度は、 4 つの問いで決まる:

  1. 1 つの A に対し、 B は最小何個?(0 or 1)
  2. 1 つの A に対し、 B は最大何個?(1 or 多)
  3. 1 つの B に対し、 A は最小何個?(0 or 1)
  4. 1 つの B に対し、 A は最大何個?(1 or 多)

🔬 数式を言葉で読み解く

🔬 数式・定義を「言葉」で読み解く

「ER 図」は単なる絵ではなく、 厳密な意味を持つ記号体系です。 1 つ 1 つを正確に理解しないと、 後の DB 設計で破綻します。

1. 🎯 「エンティティ」とは何か

エンティティ(Entity)は、 業務上識別できる「もの」「人」「事象」を指します。 「会員」「本」「貸出記録」など。 物理的なものに限らず、 「予約」「契約」「イベント」のような抽象概念も含む。 ポイントは「同じ種類の複数の実体(インスタンス)」を抱える「型」であること。

2. 📥 「属性」とは何か

3. 🧠 「リレーションシップ」と多重度

リレーションシップ(Relationship)は、 エンティティ間の 「関係」を表します。 動詞で命名するのが定石(「借りる」「所属する」「書く」)。 重要なのは 多重度(cardinality)

4. 🔍 「関連テーブル」の重要性

多対多関係を物理 DB に落とすには、 関連テーブル(associative entity, junction table)が必須です。 例:「学生 ─ 履修 ─ 講義」と、 中間に履修テーブルを作る。 履修テーブルの PK は (学生 ID, 講義 ID) の複合主キー。 さらに「履修日」「成績」などの履修固有の属性をそこに置く。 これを ER 図上で「履修」エンティティとして明示的に描くのが論理設計のポイント。

5. 💬 「概念モデル → 論理モデル → 物理モデル」の三段階

6. 📚 正規化との連携

ER 図を描いた後、 各エンティティに対し 正規化を適用:

7. 🎨 非正規化(denormalization)の判断

読み取り性能のために、 あえて正規形を崩すことがあります(非正規化)。 「同じデータが複数箇所にコピーされる」リスクと、 「JOIN なしで読める」メリットのバランス。 DWH や OLAP では非正規化が定石(スタースキーマ、 スノーフレーク)。

🧮 実値で計算してみる — SSDSE-B-2026

SSDSE-B-2026 を RDB に格納するための ER 図設計を具体的に行います。

1. 元データの形

SSDSE-B-2026 は CSV 1 枚で、 行=年度×都道府県(47 県 ×1 年 = 47 行)、 列=112 個の指標(人口、 出生数、 病院数、 etc.)。 これを「1 テーブル」で持つのは正規化的に NG。

2. 概念モデル

[Prefecture] --(1..*)-- [YearlyStat] --(*..1)-- [Year]
                            |
                       多くの数値属性
    

3. 論理モデル — テーブル分割案 A(属性をワイドのまま)

4. 論理モデル — テーブル分割案 B(縦持ち、 EAV)

案 B は「指標が増えてもテーブル構造を変えずに済む」柔軟性が高いが、 SELECT に JOIN が必要で複雑。 案 A は単純だが列数が爆発する。

5. 物理モデル(PostgreSQL)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CREATE TABLE prefectures (
  pref_code  CHAR(6)      PRIMARY KEY,
  pref_name  VARCHAR(20)  NOT NULL,
  region     VARCHAR(20)
);

CREATE TABLE indicators (
  indicator_code VARCHAR(10) PRIMARY KEY,
  name           VARCHAR(100),
  unit           VARCHAR(20),
  description    TEXT
);

CREATE TABLE observations (
  id            BIGSERIAL  PRIMARY KEY,
  pref_code     CHAR(6)    REFERENCES prefectures(pref_code),
  year          SMALLINT,
  indicator_code VARCHAR(10) REFERENCES indicators(indicator_code),
  value         DOUBLE PRECISION,
  UNIQUE (pref_code, year, indicator_code)
);

CREATE INDEX idx_obs_pref_year ON observations(pref_code, year);
CREATE INDEX idx_obs_indicator ON observations(indicator_code);

6. 多重度の検証

7. クエリ例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-- 47 都道府県の 2023 年高齢化率トップ 10
SELECT
  p.pref_name,
  obs.value AS aging_rate
FROM observations obs
JOIN prefectures p ON obs.pref_code = p.pref_code
WHERE obs.indicator_code = 'AGING_RATE'
  AND obs.year = 2023
ORDER BY obs.value DESC
LIMIT 10;

8. 元 CSV の縦持ち化スクリプト

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) B4101(年平均気温) F3101(新規求職申込件数(一般)) I510120(一般病院数) 北海道 5,092,000 1,681,000 11.0 156,458 464 東京都 14,086,000 3,205,000 17.6 270,954 588 沖縄県 1,468,000 350,000 23.8 43,877 76 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])

# wide → long
indicators = ['A1101', 'A1303', 'B4101', 'F3101', 'I510120']
long_df = df.melt(
    id_vars=['SSDSE-B-2026', 'Code', 'Prefecture'],
    value_vars=indicators,
    var_name='indicator_code',
    value_name='value'
)
long_df.rename(columns={'SSDSE-B-2026': 'year', 'Code': 'pref_code'}, inplace=True)
long_df.to_csv('observations.csv', index=False)
print(long_df.head())
print(f'rows: {len(long_df)}')
📤 実行例(実測) year pref_code Prefecture indicator_code value 0 2023 R01000 北海道 A1101 5092000.0 1 2022 R01000 北海道 A1101 5140000.0 2 2021 R01000 北海道 A1101 5183000.0 3 2020 R01000 北海道 A1101 5224614.0 4 2019 R01000 北海道 A1101 5259000.0 rows: 2820

9. インデックス設計

「県別+年度」検索が多いなら (pref_code, year) の複合インデックス。 「指標別」検索なら (indicator_code) 単独インデックス。 全部にインデックスを張ると INSERT が遅くなる。 トレードオフ。

10. 拡張性

将来 SSDSE-B-2027, 2028 が出ても、 observations テーブルに INSERT するだけで済む。 これが 正規化された ER 設計の強み

🧮 数式に値を入れて手で計算する: 多対多解消で増える表数

合成データで n×m 関係を中間表で正規化する場合のテーブル数を計算する。

Step 1: 元のエンティティ

関係表数 (含中間)
学生-科目 (n:m)3
顧客-商品 (n:m)3
論文-著者 (n:m)3
部署-プロジェクト (n:m)3

Step 2: 合計

4 関係 × 3 表 = 12 表 元のエンティティ数: 8 (4 関係 × 2) 中間表追加: +4 合計: 8+4 = 12 表

🐍 Python で再現

1
2
3
4
5
6
7
n_relations = 4
entities = 2 * n_relations
junction = n_relations
total = entities + junction
print(f"エンティティ: {entities}")
print(f"中間表: {junction}")
print(f"合計表数: {total}")

📤 実行結果

エンティティ: 8 中間表: 4 合計表数: 12

💬 手計算 (Step 2) 12 と Python 出力が完全一致。

🐍 Python 実装

① SQLAlchemy で ER モデルを Python クラスで定義

🎯 目的

SSDSE-B-2026 用のテーブル構造を SQLAlchemy ORM で定義する。 Python コードが ER 図と直接対応。

📥 入力

SQLAlchemy 2.x、 PostgreSQL 接続情報。

📤 出力

Python クラス定義、 CREATE TABLE 文が自動生成される。

💬 解釈

「コード ⇄ ER 図」の双方向同期。 Alembic でマイグレーション自動化。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from sqlalchemy import create_engine, Column, String, Integer, Float, ForeignKey
from sqlalchemy.orm import declarative_base, relationship

Base = declarative_base()

class Prefecture(Base):
    __tablename__ = 'prefectures'
    pref_code = Column(String(6), primary_key=True)
    pref_name = Column(String(20), nullable=False)
    region = Column(String(20))
    observations = relationship('Observation', back_populates='prefecture')

class Indicator(Base):
    __tablename__ = 'indicators'
    indicator_code = Column(String(10), primary_key=True)
    name = Column(String(100))
    unit = Column(String(20))
    observations = relationship('Observation', back_populates='indicator')

class Observation(Base):
    __tablename__ = 'observations'
    id = Column(Integer, primary_key=True, autoincrement=True)
    pref_code = Column(String(6), ForeignKey('prefectures.pref_code'))
    year = Column(Integer)
    indicator_code = Column(String(10), ForeignKey('indicators.indicator_code'))
    value = Column(Float)
    prefecture = relationship('Prefecture', back_populates='observations')
    indicator = relationship('Indicator', back_populates='observations')

engine = create_engine('postgresql://user:pass@localhost/ssdse')
Base.metadata.create_all(engine)

② pgAdmin / DBeaver でリバースエンジニアリング

🎯 目的

既存 DB から ER 図を自動生成する。 リバースエンジニアリングと呼ばれる。

📥 入力

DB 接続情報、 対象スキーマ。

📤 出力

ER 図(PNG / SVG)、 テーブル一覧。

💬 解釈

巨大なレガシー DB の構造把握に有効。 ただし命名規則の悪い DB だと自動図も読みにくい。

1
2
3
4
5
6
7
8
# pgAdmin の手順(GUI 操作):
# 1. 対象 DB に接続
# 2. Schema → Right click → Generate ERD
# 3. PDF / PNG で保存

# CLI 版(schemaspy):
# java -jar schemaspy.jar -dp postgresql.jar -t pgsql \
#   -host localhost -db ssdse -u user -p pass -o ./erd_out

③ Mermaid でテキストから ER 図を描く

🎯 目的

Markdown 互換の Mermaid 記法で、 ER 図をテキストで管理。 GitHub・Notion で自動レンダリング。

📥 入力

テキストエディタ。 専用ツール不要。

📤 出力

ER 図の SVG。

💬 解釈

git diff で変更履歴が追える。 ドキュメントを「コード化」する DevOps 文化の一環。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
erDiagram
    PREFECTURE ||--o{ OBSERVATION : has
    INDICATOR ||--o{ OBSERVATION : measured
    PREFECTURE {
        string pref_code PK
        string pref_name
        string region
    }
    INDICATOR {
        string indicator_code PK
        string name
        string unit
    }
    OBSERVATION {
        int id PK
        string pref_code FK
        int year
        string indicator_code FK
        float value
    }

④ DrawIO で対話的に ER 図を描く

🎯 目的

無料の Web GUI ツールで ER 図を視覚的に作成。 IE 記法・Chen 記法・UML どれも対応。

📥 入力

ブラウザ、 Google アカウント(保存用、 任意)。

📤 出力

.drawio / SVG / PNG ファイル。

💬 解釈

テキストエディタが苦手な人向け。 チームで共同編集も可(Google Drive 連携)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- drawio はテキストベースの XML を内部で持つ -->
<mxfile>
  <diagram>
    <mxGraphModel>
      <root>
        <mxCell vertex="1" value="Prefecture\npref_code (PK)\npref_name\nregion"/>
        <mxCell vertex="1" value="Observation\nid (PK)\npref_code (FK)\nyear\nvalue"/>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>

⑤ Alembic で ER モデル変更のマイグレーション

🎯 目的

SQLAlchemy モデルの変更を、 DB マイグレーションスクリプトに自動変換。 ER 図の進化を git で管理。

📥 入力

SQLAlchemy モデル変更後の状態。

📤 出力

versions/xxx_add_region.py のようなマイグレーション。

💬 解釈

本番 DB へ alembic upgrade head で適用。 ロールバックも可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# alembic init alembic
# 設定ファイル env.py に Base.metadata を登録

# モデル変更後:
# alembic revision --autogenerate -m "add region column"
# alembic upgrade head

# 出力例(versions/abc123_add_region.py):
def upgrade():
    op.add_column('prefectures',
        sa.Column('region', sa.String(length=20)))

def downgrade():
    op.drop_column('prefectures', 'region')

⑥ Mermaid + 自動 PR チェック(CI 統合)

🎯 目的

PR で ER 図 (.md) を変更したら、 GitHub Actions が自動でレンダリング・テキスト diff をコメント。

📥 入力

.github/workflows/erd-render.yml、 Mermaid ファイル。

📤 出力

PR コメントに最新 ER 図画像、 変更点リスト。

💬 解釈

レビュアーが「絵」で差分を確認できる。 ドキュメント=コード文化の典型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
name: ERD Render
on:
  pull_request:
    paths: ['docs/erd.md']
jobs:
  render:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: neenjaw/compass-mermaid-action@v1
        with:
          mermaid-files: docs/erd.md
      - run: |
          gh pr comment ${{ github.event.pull_request.number }} \
            --body "Updated ER diagram → $ARTIFACT_URL"

⚠️ 落とし穴 — よくある失敗 5 件

多対多を直接モデル化
現代 RDB では多対多は表現できない(外部キーは 1 つの値しか持てない)。 必ず関連テーブルで解消。 設計初期にここを見抜けないと、 物理化で破綻。
属性の冗長化(非正規化)
「テーブルを増やすのが面倒」と 1 テーブルに 100 カラム詰め込むと、 更新異常・データ不整合が頻発。 まず正規化、 必要なら意図して非正規化、 の順。
命名規則の混乱
userid / user_id / userId / UserID が混在すると保守不能。 プロジェクト開始時に snake_case 統一などのルールを文書化。
削除の連鎖を考えない
親テーブル削除時に子はどうなる? CASCADE、 SET NULL、 RESTRICT を意図的に選ぶ。 デフォルト RESTRICT のまま運用すると、 削除できないデータが残り肥大化。
ER 図がコードとずれる
ER 図 .png を 1 回作って終わり、 実 DB と乖離。 Mermaid・PlantUML でコード化し、 CI で自動更新検証するのが現代的。

🗺 概念マップ

ER 図を中心とした概念ツリー:

データモデリング
├─ 概念モデリング
│  ├─ ER 図 (ERD)  ← この用語
│  │  ├─ Chen 記法
│  │  ├─ IE 記法 (Crow's Foot)
│  │  ├─ Barker 記法
│  │  └─ IDEF1X
│  ├─ UML クラス図
│  └─ ファクト指向モデリング (ORM)
├─ 論理モデリング (正規化)
└─ 物理モデリング (DBMS 固有)

派生・関連:
├─ ディメンショナルモデリング (DWH)
│  ├─ スタースキーマ
│  └─ スノーフレークスキーマ
├─ Data Vault モデリング
├─ NoSQL 設計パターン
│  ├─ ドキュメント (MongoDB)
│  ├─ KVS (Redis, DynamoDB)
│  ├─ カラムストア (Cassandra)
│  └─ グラフ (Neo4j)
└─ Event Sourcing

📜 歴史と系譜

ER 図の歴史を整理。

1. 1970: コッドのリレーショナルモデル

エドガー・F・コッドが「A Relational Model of Data for Large Shared Data Banks」を発表。 リレーショナルデータベースの理論的基盤を確立。

2. 1976: チェンの ER モデル

Peter Chen が論文「The Entity-Relationship Model — Toward a Unified View of Data」を発表。 「エンティティ」「リレーションシップ」「属性」の 3 要素で DB 構造を表現する手法を提唱。 ER 図の誕生。

3. 1981: IE 記法(クロウフット)

James Martin の Information Engineering で「クロウフット(鳥の足)」記法が普及。 Chen 記法より省スペースで読みやすく、 現代の主流に。

4. 1985: SQL 標準化

ANSI SQL 標準化。 ER 図から SQL DDL への変換が体系化される。 ER 図 → CREATE TABLE 文 の機械的変換が可能に。

5. 1990s: CASE ツールの普及

ERwin、 ER/Studio、 PowerDesigner などの専用ツールが企業で広く採用。 ER 図のラウンドトリップ(順方向・逆方向同期)が実現。

6. 2000s: UML の隆盛

UML クラス図が ER 図の代替候補として浮上。 ただし DB 専用の表現力では ER 図が依然優位。

7. 2010s: NoSQL とスキーマレス

MongoDB、 Cassandra、 DynamoDB の登場で「スキーマレス」が流行。 ER 図不要論も。 しかし大規模システムでは結局スキーマ設計が必要、 という揺り戻し。

8. 2020s: ドキュメント・アズ・コード

Mermaid、 PlantUML、 dbdiagram.io でテキストベース ER 図が普及。 git で変更履歴管理、 CI で自動レンダリング。 DevOps 文化との融合。

🔧 実装詳細

ER 図実装の細部。

1. ツール選定

2. 命名規則

3. データ型の選定

4. 制約の活用

5. インデックス設計

⚙️ 運用とトラブルシュート

ER 図運用での難題。

1. 仕様変更への追随

業務要件は変わり続ける。 ER 図も常にアップデート。 ツール選定時に「ラウンドトリップ可能性」を確認。

2. マイグレーション

Alembic、 Flyway、 Liquibase でスキーマ変更を git 管理。 本番反映前にステージングで検証。

3. パフォーマンスチューニング

EXPLAIN ANALYZE で実行計画確認。 SELECT 遅延は (a) インデックス追加、 (b) クエリ書き換え、 (c) パーティション、 (d) 非正規化 の順で対処。

4. ドキュメント生成

schemaspy、 sqldef、 tbls で DB スキーマから ER 図とドキュメントを自動生成。 README で公開。

5. データ品質

参照整合性、 制約、 トリガーで DB レベルで品質確保。 アプリ層だけに頼らない。

💴 コストと見積もり

ER 図関連のコスト。

1. ツール費用

ツール料金ライセンス
DrawIO無料ASL
Mermaid無料MIT
dbdiagram.io無料 / 9 ドル/月クラウド
Lucidchart8–9 ドル/月クラウド
ERwin3,000 ドル+/年商用
ER/Studio2,000 ドル+/年商用

2. 設計フェーズの人的コスト

中規模システム(50 テーブル程度)の初期 ER 設計:シニアエンジニア 1 名 × 1 ヶ月 ≈ 150 万円。 修正フェーズはさらに同程度。

3. 教育コスト

新人エンジニアに ER 図の読み書きを教えるのに 20〜40 時間。 OJT で覚えさせる方が定着率高い。

🛡 ガバナンス・セキュリティ

ER 図関連のガバナンス。

1. データオーナーシップ

各エンティティの所有部門を明確化。 個人情報(人)は人事部、 売上(売上)は経理部、 など。 RACI マトリクス。

2. データ品質管理

DAMA 6 次元(正確性・完全性・一貫性・適時性・一意性・妥当性)で各エンティティを評価。

3. 個人情報の取り扱い

個人情報を含むカラムに「PII」フラグ。 暗号化、 アクセスログ、 匿名化を必須化。

4. データ系譜(Data Lineage)

エンティティ間のデータの流れを記録。 Apache Atlas、 OpenLineage で自動化。

5. 監査

DB 構造変更履歴を git で管理。 SOX 法、 J-SOX 対応。

🏭 産業事例 6 件 — 現場ではどう使われているか

1. EC サイトの商品・注文 ER 設計

Amazon・楽天規模の EC では、 商品(products)、 注文(orders)、 注文明細(order_items)、 顧客(customers)、 配送先住所(addresses)が中核エンティティ。 多対多はすべて関連テーブルで解消。 1 日数百万件の注文をさばくため、 パーティション・シャーディング前提の設計。

2. 銀行口座管理システム

顧客(customers)、 口座(accounts)、 取引(transactions)、 支店(branches)。 transactions は append-only(更新・削除なし、 補正取引で対応)が金融業界のお作法。 ER 図に「監査列」(created_by、 created_at)必須。 BCBS 239(バーゼル委員会のデータガバナンス原則)への対応。

3. 病院電子カルテシステム

患者(patients)、 診療(encounters)、 処方(prescriptions)、 検査(lab_results)、 医師(doctors)。 HL7 FHIR 標準に準拠した ER 設計。 個人情報の最も厳格な扱いが必要で、 3 省 2 ガイドラインに準拠。

4. 社員・人事・給与システム

社員(employees)、 部署(departments)、 役職(positions)、 給与(salaries)、 評価(evaluations)。 「社員 ⇄ 部署」が多対多(兼務)。 給与は履歴管理必須(valid_from、 valid_to で時系列)。 SCD Type 2 パターン。

5. 学校の学生・履修管理

学生(students)、 講義(courses)、 履修(enrollments)、 教員(faculty)。 「学生 ⇄ 講義」の多対多を履修テーブルで解消、 「成績」「履修日」を履修テーブルに付加。 ER 図設計の教科書的例。

6. 公共統計データの DB 化(SSDSE 風)

都道府県(prefectures)、 指標(indicators)、 観測値(observations)の 3 テーブル構成。 数百種の指標を観測値テーブルの 1 行ずつに正規化することで、 指標追加に強い柔軟な設計に。 国立統計研究所、 RESAS、 e-Stat の内部構造もこの方向。

📊 ER 図記法の比較

記法発案者エンティティ関係多重度現代利用
Chen 記法Peter Chen1976四角菱形1, N, M:N教育・学術
IE 記法 (Crow's Foot)James Martin1981四角(属性列挙)クロウフット商用主流
Barker 記法Richard Barker1985角丸四角線(点線含む)破線/実線Oracle 文化
IDEF1X米国空軍1985四角記号政府機関
UML クラス図Booch/Rumbaugh/Jacobson1995四角(区画分け)0..1, 1..*OOP 統合

📋 正規化レベル早見表

ER 図設計で頻出する「第 N 正規形」の到達条件と典型的なユースケースを表に整理する。 SSDSE-B-2026 のような分析用データセットでは 3NF が標準だが、 DWH では意図的に 2NF に留めるケースもある。

正規形到達条件解消する問題典型用途
1NF各セルがアトミック値繰り返し項目あらゆる RDB の前提
2NF1NF + 部分関数従属の排除複合 PK の冗長業務系 DB の最低ライン
3NF2NF + 推移的関数従属の排除更新異常OLTP 標準
BCNF3NF + すべての決定子が候補キー多値依存厳密な業務系
4NF / 5NF多値・結合依存の排除結合損失研究・学術

🗂 SSDSE-B-2026 を ER 図化する際の典型カラム対応

SSDSE-B-2026 (47 都道府県 × 多変量年次データ) を RDB スキーマに落とす際の対応関係を示す。 「年×都道府県」が複合 PK、 指標は属性 (人口・出生数など) となる。

SSDSE 列論理名PK / FK備考
SSDSE-2026SMALLINTPK (一部)2010–2024 等
都道府県コードpref_codeCHAR(6)PK + FKR01100 など
都道府県名pref_nameVARCHAR(8)属性正規化なら別表
A1101総人口BIGINT属性千人単位
A130365 歳以上人口BIGINT属性高齢化率算出元

📝 演習 5 問 — 理解度チェック

Q1. 「学生」と「サークル」が多対多関係の場合、 関連テーブルは何が必要?
A1. memberships テーブル:(student_id, club_id) の複合 PK。 + 加入日 (joined_at)、 役職 (role)、 など履歴情報を付加。 これで多対多を 1 対多 × 2 に分解。
Q2. 商品テーブルに「カテゴリ階層」を持たせる方法は?
A2. (a) parent_id で自己参照(再帰)、 (b) closure table(祖先と子孫の全ペアを別テーブルに)、 (c) materialized path('/food/fruit/apple' のような文字列)、 (d) nested set。 用途次第。
Q3. 注文テーブルに「合計金額」を保存すべきか、 動的計算すべきか?
A3. 両論。 保存:読み取り高速、 ただし更新時の整合性確保が必要。 動的計算:常に正確、 ただし負荷高。 EC では「注文時点の確定額」として保存するのが多い(後で価格変更があっても注文書は不変)。
Q4. 「住所」を別エンティティに切り出すべきタイミングは?
A4. (a) 同じ住所を複数主体(顧客、 配送先、 請求先)が共有、 (b) 住所だけ独立した属性(緯度経度、 行政コード)を持つ、 (c) 住所変更履歴を追跡したい、 のいずれかなら切り出す。 単純な「1 人 1 住所」なら同テーブルでも OK。
Q5. ER 図に書くべきでないものは?
A5. 派生属性(calculated columns)、 一時テーブル、 物理キャッシュ(マテビュー)。 これらは概念モデルではなく物理モデルの話。 ER 図は「業務上意味のあるもの」だけ。

💥 現場の失敗例 — こうして詰んだ

正規化を無視して 1 テーブル 200 カラム
ある SaaS で「面倒だから」と users テーブルに住所・電話・好み・購買履歴を全部詰めたら、 1 行 8 KB を超え、 更新が頻発するうちにロック競合で死亡。 後から正規化するのは設計時の 10 倍コストかかった。
外部キー制約なし → 孤児レコード大量発生
「パフォーマンス重視で FK 制約を外す」と、 親が削除されても子が残り、 集計が狂う。 整合性チェックバッチで毎晩発見・除去という綱渡り運用。 結局 FK を後付けすることになる。
ER 図を作って終わり、 実 DB と乖離
Confluence に PNG で貼ったきり、 3 年後にエンジニアが見たら全然違う構造になっていた。 Mermaid 化 + CI 必須。

❓ よくある質問 (FAQ) 10 問

Q. ER 図と UML クラス図、 どちらを使うべき?

A. DB 設計が主なら ER 図、 ソフトウェア設計と統合したいなら UML。 ER 図は「データ」、 UML は「データ+振る舞い」。 用途に応じて。

Q. NoSQL でも ER 図は必要?

A. MongoDB、 Cassandra でも「コレクション間の関係」を可視化する価値あり。 ただし正規化原則は緩い。 アクセスパターン中心の設計が重要。

Q. 無料ツールでおすすめは?

A. DrawIO(GUI)、 Mermaid(テキスト)、 dbdiagram.io(DSL)。 用途で使い分ける。

Q. チームで共同編集するには?

A. Mermaid / PlantUML をテキストで git 管理 + CI で画像化が最強。 Miro / Lucidchart などのリアルタイム共同編集も選択肢。

Q. 既存 DB から ER 図を生成できる?

A. Yes。 pgAdmin、 MySQL Workbench、 DBeaver、 schemaspy で自動生成。 ただし命名規則が悪い DB だと読みづらい。

Q. 第 3 正規形まで満たせば十分?

A. 業務系なら 3NF が標準。 OLAP / DWH では意図的に非正規化(スタースキーマ)。 用途次第。

Q. ER 図の更新はどのタイミング?

A. スキーマ変更 PR と同じタイミング。 Mermaid 化していれば自動。 「文書更新を後回しにしない」が鉄則。

Q. ER 図と論理モデルは何が違う?

A. 概念モデル(業務寄り)→ 論理モデル(RDB 設計、 正規化済み)→ 物理モデル(特定 DBMS 向け)。 ER 図は概念〜論理を表現する。

Q. エンティティ名は単数?複数?

A. テーブル名は複数形(users、 orders)、 ER 図上のエンティティ名は単数(User、 Order)が多数派。 流派次第。

Q. ER 図の学習に最適な書籍は?

A. 『達人に学ぶ DB 設計徹底指南書』(ミック著)、 『SQL アンチパターン』(Karwin 著)、 『リレーショナルデータベース入門』(増永良文著)。

ER 図 正規化 主キー / 外部キー テーブル設計 SQL データベース RDB / RDBMS

🔗 隣接手法への橋渡し

ER 図は単独の作図ではなく、 業務分析 ・正規化 ・物理 DB 設計 ・SQL DDL 生成を結ぶ設計ドキュメントである。 エンティティ ・関係 ・属性 ・カーディナリティを業務要件と紐付けて記述する。

ER 図は「実体 (Entity) ・関係 (Relationship) ・属性で DB スキーマを表現する」設計手法で、 上流の業務要件分析でエンティティを抽出し、 並列の UML クラス図・正規化と組み合わせ、 下流の物理 DB 設計・SQL DDL 生成へと運ぶ。

🌳 意思決定ツリー — 状況別の手順

ER 図の選定・運用での意思決定をツリーで整理。

🌳 ツリー 1: 採用すべきか

現状システムに課題があるか?
├─ Yes → 課題はコスト/性能/拡張性/信頼性?
│  ├─ コスト → ROI 試算で ER 図 採用検討
│  ├─ 性能 → ベンチマークで比較
│  ├─ 拡張性 → スケーラビリティ要件を整理
│  └─ 信頼性 → SLA, MTBF を比較
└─ No → 「動いているものは触らない」原則
    

🌳 ツリー 2: アーキテクチャ選定

ワークロードの特性は?
├─ 予測可能・常時稼働 → リザーブド/専有
├─ 変動大・短期 → サーバーレス/スポット
├─ レイテンシ厳しい → エッジ/フォグ
└─ コンプライアンス厳しい → プライベート/オンプレ
    

🌳 ツリー 3: トラブル対応

症状は?
├─ 完全停止 → ロールバック先行、 原因究明は後
├─ 性能劣化 → メトリクス/ログ/トレースで根因分析
├─ コスト急増 → 利用量分析、 不正アクセス疑い
└─ セキュリティイベント → CSIRT 起動、 隔離
    

📝 補足:直感を「三要素」で描き直す

ER 図の本質は、 世界を 3 つの品詞に分けて絵にすることだと捉えると迷わない。 これは前述の「組織図+家系図」の比喩を、 文法の言葉で言い換えたものである。

ER 三要素=品詞のアナロジー
  • エンティティ(実体)=名詞:「都道府県」「年度」「観測値」。 数え上げられる “もの・こと” の 。 個々の東京都・大阪府は「インスタンス」。
  • 属性=その名詞を修飾する情報:都道府県の「名前」「地方区分」「総人口」。 1 セル 1 値が原則(第 1 正規形)。
  • 関連(リレーション)=動詞:都道府県が観測値を「持つ」、 年度に観測値が「属する」。 動詞で命名すると多重度を考えやすい。

1. SSDSE-B-2026 の実測で三要素を確認する

実データ(SSDSE-B-2026.csv、 cp932、 skiprows=[1])は 564 行 × 112 列。 内訳を三要素に写像すると次のとおり。 これは捏造ではなく実ファイルの形状に一致する。

CSV 上の実測ER 三要素での役割設計上の帰結
行数 564 = 47 × 12「都道府県」47 と「年度」12(2012–2023)の直積がインスタンス1 行 = (県, 年) の 1 観測 → 複合主キー候補
先頭 3 列(SSDSE-B-2026=年, Code, Prefecture)識別のためのキー属性Code(R01000 等) が県の PK、 年と組んで複合 PK
残り 109 列(A1101 総人口 ほか)観測値の測定属性ワイドのままか、 縦持ち(EAV)で指標を実体化するかの分岐

たとえば 2023 年の総人口列 A1101 は東京都=14,086,000 が最大値(実データ)。 この 1 マスは「実体=都道府県(東京都)、 年度(2023)」×「属性=総人口」の交点にすぎない。 1 マスを主キーで一意に特定できることが、 ER 図がめざす「行の意味の明確化」である。

2. 多重度を「4 つの問い」でなく「矢印の向き」で掴む

数式セクションの 4 問法を、 直感側から補う。 「片側から相手を見たとき何本の線が出るか」だけを見る。

都道府県 ─ 観測値 の例:1 つの都道府県からは 12 本(12 年度分)の観測値へ線が伸びる=。 逆に 1 つの観測値から都道府県へは 1 本だけ=1。 よって 都道府県 1 : N 観測値。 「多」の側(観測値)に鳥の足(クロウフット)が付く。 上の 🎮 ウィジェットで N:M を選び「分解」すると、 まさにこの 1:N が 2 本生まれる様子を確認できる。

3. PK / FK は図の上でどう描かれるか

関連ページ:主キー外部キーテーブルデータベースRDB 詳細

📝 補足:落とし穴の深掘り(重要)

冒頭「落とし穴 5 件」を、 原因まで遡って整理する。 表面の症状だけ覚えても再発するので、 「なぜ起きるか」を押さえる。

1. なぜ多対多は「中間テーブルなし」で表現できないのか

外部キーは 1 つの値しか保持できない(スカラー)。 「学生」テーブルに「履修科目 FK」を 1 列置いても、 1 学生は科目を 1 つしか指せない。 逆に「科目」側に「学生 FK」を置いても対称に破綻する。 したがって M:N は原理的に 連関(中間)テーブルへ分解し、 (学生ID, 科目ID) の複合主キーで 2 本の 1:N に落とすしかない。 関係固有の属性(成績・履修日)はその連関テーブルに宿る。 これは「設計の好み」ではなく 関係モデルの制約である。

2. 多重度の誤り — 1:N と N:M の取り違え

「1 県に複数の観測値」だけ見て 1:N と決めると、 反対向き(1 観測値は何県に属すか)を検証し忘れる。 両方向を必ず問う。 SSDSE では「1 観測値 = ちょうど 1 県」なので安全に 1:N。 だが「県 ─ 指標」を素朴に結ぶと、 1 県は多指標・1 指標は多県で N:M になり、 連関テーブル(=観測値)が必要になる。 実は SSDSE の 109 指標列は、 この N:M を暗黙に横持ちで潰した状態と読める。

3. 正規化「不足」と「過剰」は両方が罠

症状正規化不足(冗長)正規化過剰
典型1 表に 109 列+県名を毎行反復指標ごとに別表、 型ごとに別表へ細断
更新異常・矛盾(県名の表記ゆれ)JOIN 爆発で読み取りが激重
対処県マスタへ分離(3NF)意図的な非正規化・まとめ直し

原則は 「まず 3NF、 必要なら意図して崩す」。 崩す判断(非正規化)は性能計測の後に行う。 早すぎる非正規化は技術的負債になる。

4. 弱実体(weak entity)の扱い

単独では識別できず、 親に依存する実体を 弱実体と呼ぶ。 自分だけでは主キーを構成できず、 親の PK+自分の部分キーで複合 PK を作る(識別関係)。 SSDSE の「観測値」は、 都道府県と年度がないと意味を持たない典型的な弱実体で、 PK は (Code, 年)。 弱実体を強実体と誤認して代理キー(連番 id)だけ振ると、 (Code, 年) の一意性制約を張り忘れ、 重複行が忍び込む。

ありがちミス:観測値に id BIGSERIAL PRIMARY KEY だけ付け、 (Code, 年, 指標) の UNIQUE を忘れる → 同じ (県, 年, 指標) が 2 行入っても DB は気づかない。 代理キーを使う場合も 業務上の一意性は UNIQUE 制約で別途保証する。

5. 命名の一貫性

同じ概念が pref_code / prefCode / 都道府県コード / Code と揺れると、 JOIN 条件で人的ミスが多発する。 プロジェクト開始時に snake_case 統一・FK は参照先_id 形式などを文書化し、 SSDSE の日本語列(年度・Code・Prefecture)も論理名へ正規化してから設計に入る。

6. 概念 / 論理 / 物理設計の混同

層の取り違え
概念モデルの段階で「INT か BIGINT か」「どの列にインデックスを張るか」を議論し始めると、 業務の合意形成が止まる。 逆に物理モデルで「そもそもこの実体は要るか」を蒸し返すと手戻りが巨大化。 概念(業務語・多対多 OK)→ 論理(PK/FK・正規化・DB 中立)→ 物理(型・索引・DBMS 依存)の順に、 各層で決めることを混ぜない。

📝 補足:発展 — 変換・正規化・記法・NoSQL

1. ER 図 → リレーショナルスキーマの機械的変換規則

ER 図は、 ほぼ機械的に表定義へ落とせる。 この 7 つの規則を覚えると設計が速い。

ER 上の要素変換規則SSDSE での適用
強実体1 実体 → 1 表、 主キーはそのまま PKprefectures(Code PK)
1:1 関連どちらか一方に FK(NULL 少ない側に寄せる)該当薄い(統合で足りる)
1:N 関連「多」側に「1」側の PK を FK として置くobservations に Code を FK
M:N 関連連関表を新設、 両 PK を複合 PK 兼 FK にobservations が (Code, 年, 指標)
多値属性別表に切り出し 1:N 化指標を縦持ち(EAV)化
複合属性構成要素ごとに列分解住所→市/番地 等(SSDSE では不要)
弱実体親 PK + 部分キーで複合 PKobservations = (Code, 年)

2. 正規化(第 1〜3 正規形)との関係

ER 図の「論理化」は、 実体の各表に正規化を適用する工程そのもの。 テーブルの粒度を決める理論的裏付けが正規形である(本用語集に正規化の独立ページは未整備のため、 ここでは要点をテキストで示す)。

合言葉:「キー、 キー全体、 キー以外のなにものにも依存しない(The key, the whole key, and nothing but the key)」。 これが 1NF・2NF・3NF を 1 文で言い切った古典的標語。

3. 記法の違い — IE / IDEF1X / UML

比較表(📊 比較表)に加え、 実務で迷いやすい点を補う。

4. NoSQL での設計思想の違い

ER 図+正規化は「書き込みの整合性」を最優先する RDB の思想。 NoSQL は逆に アクセスパターン駆動で設計する。

観点RDB(ER 図・正規化)NoSQL(例:ドキュメント DB)
設計の起点実体と関係(データ構造)クエリ/画面(アクセスパターン)
冗長正規化で排除埋め込み(embed)で意図的に重複
結合JOIN で実行時に接続あらかじめ 1 ドキュメントに同梱
SSDSE の例県・年・観測を 3 表に分離県ドキュメントに年次配列を内包

ただし NoSQL でも「どの実体がどう関係するか」を把握する意味で ER 的思考は有効で、 スキーマレス=無設計ではない。 大規模化すると結局スキーマ設計へ回帰する、 というのが歴史セクションで触れた揺り戻しである。

📎 関連ページRDBRDB 詳細データベース主キー外部キーテーブルSQLDDLNoSQLデータウェアハウスデータ結合縦持ち・横持ち整然データSSDSEナレッジグラフ(正規化・UML クラス図・DFD の独立ページは本用語集に未整備のため、 本文中でテキスト解説)