ER図は「描く」から「書く」へ

ER図(実体関連図)をドローツールで描くと、テーブルが増えるたびに線を繋ぎ直す作業が発生し、いつの間にか実際のスキーマと図がズレていきます。Mermaidの erDiagram を使えば、ER図をテキストで管理できます。コードと同じようにdiffが取れ、GitHubのREADMEやプルリクエスト、Notion、Zennにそのまま貼れば自動で描画されます。

この記事は、erDiagram の記法を一覧表と実例で引けるリファレンスです。最後に、既存のSQL(CREATE TABLE文)からこの記法を自動生成する方法も紹介します。

最小構成:まずこの3行から

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

これだけで「USERSとPOSTSが1対多(1人のユーザーが0個以上の投稿を持つ)」という図が描画されます。構文は次の形です。

<エンティティ1> <左の多重度><線><右の多重度> <エンティティ2> : "関係ラベル"

ポイントは、関係ラベル(: 以降)が省略できないこと。ラベルを表示したくない場合も : "" と空文字列を書く必要があります。ここが最初のつまずきどころです。

リレーション記号の早見表

erDiagram の多重度記号は「カラスの足(Crow’s Foot)記法」に対応しています。記号の向きは常にエンティティ側が外側です。

記号(左側)記号(右側)意味
|oo|0または1(Zero or one)
||||ちょうど1(Exactly one)
}oo{0以上(Zero or more)
}||{1以上(One or more)

組み合わせの具体例で覚えるのが早いです。

書き方読み方
A ||--o{ BAは1、Bは0個以上(最も使う1対多
A ||--|{ BAは1、Bは必ず1個以上
A |o--o| Bどちらも0または1(任意の1対1)
A ||--|| B厳密な1対1
A }o--o{ B多対多(中間テーブルを挟む前の概念図に)

実線と破線:識別関係と非識別関係

線の部分は2種類あります。

意味使いどころ
--識別関係(実線)子が親のPKを自分のPKの一部として持つ(例: 注文明細)
..非識別関係(破線)子が親のPKを通常のFKとして持つだけ(例: 投稿と作成者)
ORDERS ||--|{ ORDER_ITEMS : "contains"     %% 識別関係(実線)
USERS  ||..o{ POSTS       : "writes"       %% 非識別関係(破線)

%% はコメントです。チームの規約として「識別/非識別を使い分けるか、実線に統一するか」を最初に決めておくと図が安定します。

属性(カラム)の定義

エンティティ名の後ろに {} ブロックを付けると、カラムを表形式で表示できます。

erDiagram
    USERS {
        int id PK "自動採番"
        varchar(255) email UK "ログインID"
        varchar(100) name
        datetime created_at
    }

1行の構成は 型 カラム名 [キー] ["コメント"] です。

  • キーPK / FK / UK の3種類。PK, FK のようにカンマ区切りで複数指定もできます(複合キーの中間テーブルで多用)
  • 型名には varchar(255) のような括弧も使えます
  • コメントはダブルクォートで囲みます

実務サンプル:ECサイトの注文まわり

ここまでの記法を全部使った、コピペで動く完全サンプルです。

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 の2本)を持つ中間テーブルに分解し、ORDERS ||--|{ ORDER_ITEMS(注文には必ず1件以上の明細がある)という業務ルールまで多重度で表現しています。

ハマりどころと回避策

  • 関係ラベルは必須。省略すると構文エラーになる。非表示にしたければ : ""
  • 日本語のエンティティ名は避けるのが無難。環境によって描画が不安定になるため、テーブル名は英語のまま、日本語は関係ラベルやコメントで補うのが安全
  • 多対多(}o--o{)は概念設計まで。物理設計に落とす段階で中間テーブルに分解する
  • GitHubで描画されないときは、コードブロックの言語指定が ```mermaid になっているかを確認

CREATE TABLE文から自動生成する

テーブルが10個を超えると、この記法を手書きするのも大変になってきます。既にDDL(CREATE TABLE文)があるなら、SQL to ER図 変換ツール に貼り付けるだけで、PK/FK・リレーションを解析したMermaid ER図を自動生成できます。

SQL to ER図 変換ツールでCREATE TABLE文からMermaid ER図を自動生成

処理は完全にブラウザ内で完結するため、機密性の高いスキーマ情報が外部に送信されることはありません。生成したコードをこの記事の早見表を見ながら手直しする、という流れが最短です。ツールの詳しい使い方はSQL DDLからER図を自動生成する方法で解説しています。

よくある質問

1対多はどう書くのが正解ですか?

親 ||--o{ 子 が基本形です(親1件に対して子が0件以上)。「子が必ず1件以上ある」ことをスキーマ上のルールとして明示したい場合だけ ||--|{ を使います。迷ったら ||--o{ にしておくのが安全です。

リレーションの線だけ書いて、属性は省略してもいいですか?

問題ありません。erDiagram はリレーション行だけでもエンティティを自動生成して描画します。設計の初期段階ではリレーションだけの概念図を書き、固まってきたら {} ブロックで属性を追記する、という段階的な書き方が実務では使いやすいです。

MermaidのER図はどこで描画できますか?

GitHub(README・Issue・PR)、GitLab、Zenn、Notion、VS Code(拡張機能)、Obsidianなど、主要なMarkdown環境の多くが対応しています。```mermaid のコードブロックとして貼り付けるだけで描画されます。対応していない環境向けには、Mermaid Live EditorやツールでSVG/PNGに書き出す方法があります。

多対多のリレーションはそのまま実装できますか?

A }o--o{ B はあくまで概念レベルの表現で、リレーショナルデータベースには多対多を直接実装できません。物理設計では本文のECサンプルのように中間テーブル(複合主キー+FK2本)へ分解します。図の段階で分解まで書いておくと、実装時の手戻りがなくなります。