別再手畫 ER 圖了

用繪圖工具畫實體關聯圖時,每新增一張表就得重新連線,圖遲早會和實際的資料庫結構脫節。用 Mermaid 的 erDiagram,圖就是純文字:存在版本庫裡、會出現在 diff 中,並且能在 GitHub README、Pull Request、Notion 等大多數 Markdown 檢視器中自動渲染。

這篇文章是一份可以隨查隨用的參考:基數對照表、屬性語法、完整的實戰範例,最後還會介紹如何直接從既有的 SQL 自動產生這一切。

最小範例:從三行開始

erDiagram
    USERS ||--o{ POSTS : "has"

光這樣就能渲染出「USERS 對 POSTS 是一對多(一位使用者擁有零篇或多篇文章)」。通用格式是:

<實體1> <左側基數><連線><右側基數> <實體2> : "標籤"

有件事要先說清楚:冒號後的關聯標籤是必填的。如果不想顯示文字,寫 : "";完全省略會造成語法錯誤,這是最常見的第一個踩雷點。

基數符號:對照表

erDiagram 的基數採用烏鴉腳(crow’s foot)表示法。符號永遠指向對應的實體。

左側符號右側符號意義
|oo|零或一
||||恰好一個
}oo{零或多個
}||{一個或多個

用具體組合來記是最快的方式:

語法讀法
A ||--o{ B一個 A,零或多個 B(最常見的一對多
A ||--|{ B一個 A,至少一個 B
A |o--o| B選擇性的一對一
A ||--|| B嚴格的一對一
A }o--o{ B多對多(加入中介表之前的概念性表示)

實線 vs 虛線:識別關聯 vs 非識別關聯

線段部分有兩種:

意義常見用途
--識別關聯(實線)子表的主鍵包含父表的 PK(例如訂單明細)
..非識別關聯(虛線)子表僅以一般 FK 參照父表(例如文章與作者)
ORDERS ||--|{ ORDER_ITEMS : "contains"     %% 識別關聯(實線)
USERS  ||..o{ POSTS       : "writes"       %% 非識別關聯(虛線)

%% 是註解。是否要區分識別關聯,還是統一用實線,由團隊自行決定——兩種做法都可以,重點是保持一致,圖才會好讀。

定義屬性(欄位)

在實體後面加上 {} 區塊,就能把欄位以表格形式渲染出來。

erDiagram
    USERS {
        int id PK "自動遞增"
        varchar(255) email UK "登入帳號"
        varchar(100) name
        datetime created_at
    }

每一行的格式是 型別 欄位名 [鍵] ["註解"]

  • 可以是 PK / FK / UK,且可以用逗號組合多個PK, FK)——這對含複合鍵的中介表來說是必要的
  • 型別可以包含括號,例如 varchar(255)decimal(10)
  • 註解要用雙引號包起來

實戰範例:電商訂單

把上述語法全部用上、可以直接複製貼上使用的完整範例:

erDiagram
    USERS ||--o{ ORDERS : "places"
    ORDERS ||--|{ ORDER_ITEMS : "contains"
    PRODUCTS ||--o{ ORDER_ITEMS : "included in"

    USERS {
        int id PK
        varchar(255) email UK
        varchar(100) name
        datetime created_at
    }
    ORDERS {
        int id PK
        int user_id FK
        varchar(20) status
        datetime ordered_at
    }
    ORDER_ITEMS {
        int order_id PK, FK
        int product_id PK, FK
        int quantity
        decimal(10) unit_price
    }
    PRODUCTS {
        int id PK
        varchar(200) name
        decimal(10) price
    }

重點在 ORDER_ITEMS:訂單與商品之間的多對多關係,被拆解成一張擁有複合主鍵(兩個 PK, FK 欄位)的中介表,而「一筆訂單必定至少有一筆明細」這條business規則,則透過 ||--|{ 的基數表示出來。

常見的坑與避開方法

  • 關聯標籤是必填的,不想顯示就寫 : ""
  • 實體名稱建議使用 ASCII。非 ASCII 名稱在不同環境下的渲染表現不一,建議資料表名稱保持英文,在地語言放進標籤或註解即可
  • 多對多(}o--o{)僅適用於概念層級的圖,實作前務必拆解成中介表
  • 在 GitHub 上無法渲染? 檢查程式碼區塊的語言標記是否精確為 ```mermaid

從 CREATE TABLE 語句自動生成

資料表一旦超過十張左右,手寫這種語法就會變得很累人。如果手邊已經有 DDL,直接貼到 SQL to ER 圖轉換工具 就好——它會解析主鍵、外鍵與關聯,自動產生 Mermaid ER 圖。

使用 SQL to ER 工具從 CREATE TABLE 語句生成 Mermaid ER 圖

整個過程完全在瀏覽器內完成,機密的資料庫結構資訊不會外流。先產生基本圖表,再對照上面的對照表微調即可。關於工具本身的詳細介紹,可參考如何從 SQL DDL 生成 ER 圖

常見問題

一對多關係該怎麼寫才正確?

父表 ||--o{ 子表 是標準寫法(一個父表,零或多個子表)。只有當「子表必須至少存在一筆」是真實的業務規則、且你想在圖上明確表達時,才使用 ||--|{。如果不確定,||--o{ 是安全的預設選擇。

可以只畫關聯、不定義屬性嗎?

可以。即使沒有 {} 區塊,erDiagram 仍會渲染關聯行中提到的實體。實務上常見的做法是:設計初期只畫關聯,等 schema 穩定後再補上屬性區塊。

Mermaid ER 圖可以在哪裡渲染?

GitHub(README、Issue、PR)、GitLab、Notion、VS Code(搭配擴充套件)、Obsidian 以及大多數現代 Markdown 環境都能原生渲染 Mermaid 程式碼區塊。其他環境則可透過 Mermaid Live Editor 匯出 SVG/PNG。

多對多關係可以直接實作嗎?

不行。A }o--o{ B 只是概念層級的表示法。關聯式資料庫需要一張中介表(複合主鍵加上兩個外鍵),就像上面的電商範例一樣。及早在圖上畫出拆解後的形式,能減少實作階段的重工。