1976 - 陳氏實體關係模型(ER 圖:資料庫設計的統一語言)#
案件摘要#
1976 年,MIT 的陳品山(Peter Chen,1947–) 在 ACM Transactions on Database Systems 發表 The Entity-Relationship Model—Toward a Unified View of Data:
在 ER 模型之前,資料庫設計者面對的是一堆表格與綱要—— 「為什麼這樣分表?」「現實世界怎麼映射進來?」沒有統一語言; Chen 提出三個基本概念: - 實體(entity):現實中可區別的「東西」(學生、課程、客戶); - 屬性(attribute):實體的性質(姓名、學分、地址); - 關係(relationship):實體之間的關聯(選課、下單、隸屬)。
ER 圖成為資料庫設計的「世界語」—— 半世紀以來,每一堂資料庫課、每一份設計文件都畫著它。
前因 -- 為什麼會有這個案子#
- 三種資料模型的三國鼎立(1970s 初):
三種模型各有自己的描述語言—— 設計方法互不相通、文件無法交換——
Chen 的論文副標題 Toward a Unified View of Data 正是這個野心。 - Codd 關聯式模型的「設計缺口」: Codd 的模型(見 1970-科德關聯式資料庫.md)告訴你 資料長什麼樣(表)與怎麼查(關聯代數)—— 但沒有告訴你怎麼從現實世界設計出這些表:
這個「\ ???\ 」正是 ER 模型要填補的洞。 - Bachmann 網路模型的啟發(1969): Charles Bachmann 的網狀模型(見 ../資訊科學/1969-巴赫曼網路模型.md ——若存在)用圖(nodes and links)描述資料—— Chen 受其啟發,但把「關係」從「集合的推廣」提升為一級概念:
(Bachmann 於 1973 年獲圖靈獎——網狀模型的功臣。) - 「語義」的覺醒: 1970s 中,學界開始問:資料的「意義」(semantics)去哪了? 表格裡的每一格只有值,沒有意義—— ER 模型是語義資料模型(semantic data model)的開山之作——
線索與推理 -- 數學式、程式、理論#
第一條線索:ER 模型的形式定義#
ER 模型 = \((E, \text{Attr}, R)\) : - \(E\) :實體集(entity sets),如「學生」「課程」; - \(\text{Attr}\) :屬性函數 \(\text{Attr}: E \to \text{值的集合}\) , 如 學生.學號 \(\in \{1, 2, \dots\}\) ; - \(R \subseteq E_1 \times E_2 \times \cdots \times E_n\) : \(n\) 元關係集。 ER 圖的畫法(Chen 的記號): - 矩形 ▭:實體;橢圓 ⬭:屬性;菱形 ◇:關係。
第二條線索:基數(cardinality)——一對一、一對多、多對多#
關係的基數決定資料的結構:
- 一對一(1:1):每人一張身分證—— \(R \subseteq E_1 \times E_2\) 且每個實體至多出現一次;
- 一對多(1:N):一部門多員工—— \(\forall r_1, r_2 \in R:\ r_1[E_1] = r_2[E_1] \Rightarrow r_1 = r_2\) ( \(E_1\) 側唯一);
- 多對多(M:N):多學生選多課程—— 無唯一性限制——
第三條線索:ER → 關聯式綱要的轉換規則#
Chen 的轉換法則(設計方法論的核心): 1. 實體集 → 表:每個實體集變成一張表,屬性變成欄位;
- 1:N 關係 → 外鍵:在「N 側」的表加外鍵(foreign key);
- M:N 關係 → 橋接表:關係集本身變成一張表, 主鍵 = 兩側主鍵的組合:
- 這三條規則機械化了資料庫設計—— 從 ER 圖到 SQL 綱要,不再需要靈感,只需要規則:
Python:用類別實作小型 ER 模型(學生-課程-選課 M:N)#
import sqlite3
# 1) ER 模型的類別表示(實體、屬性、關係)
class Entity:
def __init__(self, name, key, attrs):
self.name, self.key, self.attrs = name, key, attrs
class Relationship:
def __init__(self, name, e1, e2, cardinality, attrs=()):
self.name, self.e1, self.e2 = name, e1, e2
self.card, self.attrs = cardinality, attrs
student = Entity("學生", "學號", ["姓名", "系所"])
course = Entity("課程", "課號", ["課名", "學分"])
enroll = Relationship("選課", student, course, "M:N", ["成績"])
print("ER 模型(學生-課程-選課):")
print(f" 實體:{student.name}(鍵:{student.key},屬性:{student.attrs})")
print(f" 實體:{course.name}(鍵:{course.key},屬性:{course.attrs})")
print(f" 關係:{enroll.name}({enroll.card},屬性:{enroll.attrs})")
# 2) ER → 關聯式綱要(Chen 的轉換規則 1 與 3)
conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute(f"CREATE TABLE {student.name} ({student.key} INTEGER PRIMARY KEY, "
f"姓名 TEXT, 系所 TEXT)")
cur.execute(f"CREATE TABLE {course.name} ({course.key} TEXT PRIMARY KEY, "
f"課名 TEXT, 學分 INTEGER)")
cur.execute(f"CREATE TABLE {enroll.name} (" # M:N → 橋接表
f"學號 INTEGER, 課號 TEXT, 成績 INTEGER, "
f"PRIMARY KEY (學號, 課號), " # 組合主鍵
f"FOREIGN KEY (學號) REFERENCES 學生(學號), "
f"FOREIGN KEY (課號) REFERENCES 課程(課號))")
# 3) INSERT:把「現實世界」的資料映射進關聯式表格
students = [(1, "王大明", "資工系"), (2, "林小美", "數學系"), (3, "陳阿土", "資工系")]
courses = [("CS101", "計算機概論", 3), ("MA201", "線性代數", 3), ("CS340", "資料庫", 3)]
enrolls = [(1, "CS101", 88), (1, "CS340", 92), (2, "MA201", 95),
(2, "CS101", 78), (3, "CS101", 85), (3, "CS340", 90)]
cur.executemany("INSERT INTO 學生 VALUES (?,?,?)", students)
cur.executemany("INSERT INTO 課程 VALUES (?,?,?)", courses)
cur.executemany("INSERT INTO 選課 VALUES (?,?,?)", enrolls)
conn.commit()
# 4) 查詢:M:N 關係的威力——一次看到三個實體的交集
print("\nM:N 查詢:誰選了什麼課、成績如何?(三表 JOIN)")
for name, cname, grade in cur.execute(
"""SELECT 學生.姓名, 課程.課名, 選課.成績
FROM 選課
JOIN 學生 ON 選課.學號 = 學生.學號
JOIN 課程 ON 選課.課號 = 課程.課號
ORDER BY 學生.姓名, 課程.課名"""):
print(f" {name} × {cname}:{grade} 分")
print("\n各課程平均成績(M:N 的分組聚合):")
for cname, avg in cur.execute(
"""SELECT 課程.課名, AVG(選課.成績)
FROM 選課 JOIN 課程 ON 選課.課號 = 課程.課號
GROUP BY 課程.課名 ORDER BY 課程.課名"""):
print(f" {cname}:平均 {avg:.1f} 分")
conn.close()
ER 模型(學生-課程-選課):
實體:學生(鍵:學號,屬性:['姓名', '系所'])
實體:課程(鍵:課號,屬性:['課名', '學分'])
關係:選課(M:N,屬性:['成績'])
M:N 查詢:誰選了什麼課、成績如何?(三表 JOIN)
林小美 × 線性代數:95 分
林小美 × 計算機概論:78 分
王大明 × 計算機概論:88 分
王大明 × 資料庫:92 分
陳阿土 × 計算機概論:85 分
陳阿土 × 資料庫:90 分
各課程平均成績(M:N 的分組聚合):
線性代數:平均 95.0 分
計算機概論:平均 83.7 分
資料庫:平均 91.0 分
結案 -- 後果與影響#
- 資料庫設計方法論的誕生(1976):
此後每一本資料庫教科書都以 ER 模型為設計篇的核心—— ER 圖成為資料庫課程的必修圖。 - 業界標準(1980s–): - CASE 工具(Computer-Aided Software Engineering):ERwin、PowerDesigner—— 自動把 ER 圖轉成 SQL 綱要; - UML 的類別圖(1990s):承襲 ER 模型的語義思想;
- 正規化理論的姐妹線: Codd 的正規化(1971,1NF/2NF/3NF)告訴你表格該長什麼樣; ER 模型告訴你表格從哪裡來——
兩條線索在 1980s 合流——正規化成為檢驗 ER 設計的標準—— 這是資料庫理論的姐妹雙璧。 - 語義資料模型的譜系: ER 模型之後,語義模型蓬勃發展: - 擴充 ER(EER,1980s):加入繼承(is-a)、子類; - 物件導向模型(1990s):實體 → 物件; - 本體論(ontology)與知識圖譜(2000s–):實體與關係的 AI 版——
- Chen 的榮耀: Peter Chen 獲 ACM Fellow、多項終身成就獎—— ER 模型是資訊科學史上被引用最多的論文之一(引用數以萬計);
- 統一觀點的實現:
這個三層設計流程(概念→邏輯→物理)至今仍是所有資料庫設計的標準流程—— 而 SQL(1974) 與 Ingres(1974) 的戰場 (見 1974-錢柏林SQL.md、1974-斯東布雷克Ingres.md), 正是這個流程的邏輯與物理層。 - 歷史定位:陳品山是「資料建模之父」—— 他把 Codd 的數學(1970)與 Bachmann 的圖(1969)統合,
關鍵人物與文獻#
- P. P.-S. Chen(陳品山):The Entity-Relationship Model—Toward a Unified View of Data(ACM TODS, 1976)。
- E. F. Codd:關聯式模型(1970)與正規化(1971)——ER 的轉換目標(見
1970-科德關聯式資料庫.md)。 - C. W. Bachmann:網狀模型(1969)與圖形記法——1973 圖靈獎——ER 的啟發者。
- J. Martin:Computer Data-Base Organization(1975)等——ER 方法論的普及者。
- 相關案件:
1936-圖靈機.md、1970-科德關聯式資料庫.md、1974-錢柏林SQL.md、1974-斯東布雷克Ingres.md、1986-波斯特Postgres.md。