核心概念
Entity(實體):業務領域裡有意義的「事物」,有自己的屬性。例:User、Order、Product、Invoice。
Attribute(屬性):描述實體的特性。User 有 name、email、created_at。分辨哪些屬性是識別符(Primary Key)是第一個設計決策。
Relationship(關係):實體之間的業務連結。User 下了 Order;Order 包含 Product。
Cardinality(基數):關係的「多少」——是一對一、一對多、還是多對多?
Cardinality 的四種情況
1:1(一對一):一個 User 有一個 Profile,一個 Profile 屬於一個 User。
實作:通常合併成一張表,或把 FK 放在使用頻率較低的那邊。
1:N(一對多):一個 User 有多個 Order,每個 Order 只屬於一個 User。
實作:FK 放在「多」的那邊(orders.user_id)。
M:N(多對多):一個 Order 包含多個 Product,一個 Product 可以出現在多個 Order。
實作:需要中間表(order_items,帶 order_id + product_id)。中間表通常還有自己的屬性(數量、價格)。
1:0 or 1(可選的一對一):User 可能有 BillingAddress,也可能沒有。
實作:FK 允許 NULL,或拆成獨立表。
ER 圖的標記方式
常見的標記法有 Chen 符號、Crow’s Foot、UML Class Diagram。Crow’s Foot 最常見:
User ||--o{ Order : "places"
└── 一個 User 必須有 0 或多個 Order
Order }o--|| Product : "contains"
└── Order 包含 1 個以上的 Product(透過中間表)
工具:dbdiagram.io(DBML 語法,export SQL)、draw.io(視覺化拖拉)、Mermaid ER diagram(在 Markdown 裡畫)。
常見的 ER Modeling 錯誤
把狀態放在實體名稱裡:設計了 ActiveUser、InactiveUser——這是兩個 entity 還是一個 entity 的狀態?應該是 User + status 欄位。
把所有東西塞進一個大表:orders 表裡放了 user 資訊、billing address、shipping address、每個商品的資訊——這個表沒有辦法做任何有效的關聯查詢,而且大量重複資料。
忽略關係本身的屬性:User 加入了 Team——這個關係發生的時間、角色(admin / member)呢?這些屬性屬於 relationship,不屬於任何一個 entity,需要存在中間表 team_memberships 裡。
混淆事務和快照:Order 裡要不要存 product_name?product_price?原則是:訂單是時間點的快照,商品名稱和價格在下單後可能改變,所以訂單裡要存當時的名稱和價格,不是只存 FK 然後每次 JOIN。
ER 圖到 SQL 的翻譯
-- User 1:N Order
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
);
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Order M:N Product(透過中間表)
CREATE TABLE products (
id BIGINT PRIMARY KEY,
name VARCHAR(200) NOT NULL,
base_price DECIMAL(10, 2) NOT NULL
);
CREATE TABLE order_items (
order_id BIGINT REFERENCES orders(id),
product_id BIGINT REFERENCES products(id),
quantity INT NOT NULL,
unit_price DECIMAL(10, 2) NOT NULL, -- 快照!記錄下單時的價格
PRIMARY KEY (order_id, product_id)
);ER Modeling 是設計的語言,SQL 是實作的語言。把這兩個步驟分開,設計討論在 ER 層進行,才不會一開始就陷入 SQL 的細節而忽略業務邏輯。