Mermaid ER図エディタ
ER 図はテーブルと列、そしてテーブル同士のつながり方を示します。対象がデータベースのスキーマで、論点がキーと多重度——1 対多なのか、任意なのか、中間テーブルを挟むのか——であるときに使います。振る舞いや継承を持つ型を描きたいなら、クラス図のほうが適しています。
中間テーブルを持つ受注スキーマ
注目すべきは注文明細の `}o--||` です。多対多を、二つのテーブルが直接つながっているふりをせず、独自の列を持つ中間テーブルとして正直に表現する書き方です。単価を注文明細に持たせているのは、商品の価格が後で変わっても注文時の金額が動かないようにするためで、この判断こそ ER 図が可視化すべきものです。
erDiagram
顧客 ||--o{ 注文 : "発注する"
注文 ||--|{ 注文明細 : "明細を持つ"
商品 ||--o{ 注文明細 : "参照される"
顧客 ||--o{ 配送先 : "登録する"
顧客 {
int id PK
string email UK "小文字で保存"
string 氏名
datetime 登録日時
}
注文 {
int id PK
int 顧客id FK
string 状態
decimal 合計金額
}
注文明細 {
int 注文id PK, FK
int 商品id PK, FK
int 数量
decimal 単価 "注文時点の価格"
}
商品 {
int id PK
string 品番 UK
string 商品名
}
配送先 {
int id PK
int 顧客id FK
string 郵便番号
}実例で理解する
1. 2 つの実体と 1 つの関連
ER の関連はコロンの後のラベルが必須です。フローチャートの辺と違って省略できません。「顧客が注文を発注する」と、そのまま文として読めるように書きます。
erDiagram
顧客 ||--o{ 注文 : "発注する"2. 列を足す
属性の各行は `型 名前` で、どちらも省略できません。`PK`、`FK`、`UK` がキーを表し、末尾の引用符付き文字列はその列へのコメントになります。型は日本語でも通りますが、SQL の型をそのまま書いたほうが実装との対応が付きます。
erDiagram
顧客 ||--o{ 注文 : "発注する"
顧客 {
int id PK
string email UK
string 氏名
}
注文 {
int id PK
int 顧客id FK
datetime 発注日時 "UTC で保存"
}3. 意味のある多重度
それぞれの実体に近いほうの 2 文字が、その実体の個数を表します。この例は「注文には明細が必ず 1 行以上ある。ただし顧客は 1 件も注文していないことがある」と言っています。スキーマが実際に守るべき制約であり、図が示すべきものです。
erDiagram
顧客 ||--o{ 注文 : "発注する"
注文 ||--|{ 注文明細 : "明細を持つ"
注文明細 }o--|| 商品 : "参照する"4. 中間テーブルによる多対多
Mermaid は多対多を直接描けますが、実際のスキーマに直接の多対多はめったにありません。下に中間テーブルがあります。それを描いたほうが正直で、関連そのものが持つ列——受講日時や成績——の置き場所もできます。
erDiagram
学生 ||--o{ 受講 : "履修する"
講義 ||--o{ 受講 : "履修される"
受講 {
int 学生id PK, FK
int 講義id PK, FK
datetime 登録日時
string 評価 "採点まで null"
}
学生 {
int id PK
string 氏名
}
講義 {
int id PK
string 講義コード UK
}5. 自己参照
テーブルは自分自身と関連を持てます。組織の指揮命令系統、カテゴリの木構造、スレッド形式のコメントなどです。両端が同じ実体になるので、関連ラベルがふだん以上に効いてきます。
erDiagram
社員 ||--o{ 社員 : "管理する"
社員 {
int id PK
int 上長id FK "社長だけ null"
string 氏名
string 役職
}ER図 構文早見表
多重度は関連の両端に 2 文字ずつ書き、真ん中から外に向かって読みます。左側の 2 文字が左の実体を、右側の 2 文字が右の実体を説明します。
| 構文 | 意味 |
|---|---|
| erDiagram | 図を開始する。大文字小文字を区別する。`erdiagram` は通らない。 |
| A ||--o{ B : ラベル | 関連。ラベルは必須。 |
| || | ちょうど 1。 |
| o| | 0 または 1。 |
| }| | 1 以上。 |
| }o | 0 以上。 |
| -- | 識別関連——実線。 |
| .. | 非識別関連——破線。 |
| A { ... } | 実体 A の属性ブロック。 |
| int id PK | 属性: 型、名前、任意でキー指定。 |
| PK / FK / UK | 主キー、外部キー、一意キー。 |
| int id PK, FK | 複数のキー指定はカンマ区切り。 |
| string email "コメント" | 末尾の引用符付き文字列は列へのコメント。 |
| A ||--o{ B : "二語のラベル" | 空白を含むラベルには引用符が必須。付けないと最初の空白で切れ、残りの語が実体として増える。 |
ER図を壊す 6 つのエラー
ER 図はここで扱う 6 種類のなかで最も文法が厳格で、他の図なら通るものが容赦なく弾かれます。とはいえ静かに間違うものもあり、日本語で書くときに出やすいのはむしろそちらです。すべて Mermaid 11.12.2 で再現しました。
表示されるもの
Parse error、末尾が: Expecting 'COLON', 'STYLE_SEPARATOR', got 'NEWLINE'
原因
関連にラベルがありません。フローチャートの辺と違い、コロンとラベルは必須で、これがないと行が途中で終わったものとして扱われます。
対処
コロンと動詞句を足します。文として読める短さに収めてください。
erDiagram
顧客 ||--o{ 注文erDiagram
顧客 ||--o{ 注文 : "発注する"表示されるもの
描画はされるが、ラベルが途中で切れ、身に覚えのない実体が増えている
原因
関連ラベルに半角空白が入っているのに引用符が付いていません。Mermaid はエラーを出さず、最初の空白でラベルを打ち切り、残りの語をそれぞれ独立した実体として作ります。`注文を 出す` は「注文を」というラベルと、「出す」という空の実体になります。日本語では単語を空白で区切らないぶん遭遇しにくい一方、いざ起きると原因が分かりにくい種類の間違いです。実測では、同じ位置に全角空白を入れた場合は 1 つのラベルのまま保たれました。
対処
空白を含むラベルは必ず引用符で囲みます。全角空白でも通りますが、引用符のほうが意図が明確です。
erDiagram
顧客 ||--o{ 注文 : 注文を 出すerDiagram
顧客 ||--o{ 注文 : "注文を 出す"表示されるもの
Parse error、末尾が: Expecting 'ATTRIBUTE_WORD', got 'BLOCK_STOP'
原因
属性に名前だけあって型がありません。ER の属性は `型 名前` で、型は省略できません。スキーマレスなデータベースから来た人がまず驚くところです。
対処
すべての属性に型を与えます。実際のスキーマに型がないなら適当に決めて構いません。`string`、`int`、`json`。
erDiagram
顧客 {
メールアドレス
}erDiagram
顧客 {
string メールアドレス
}表示されるもの
Parse error、末尾が: Expecting 'NON_IDENTIFYING', 'IDENTIFYING', got 'UNICODE_TEXT'
原因
多重度の間の線が違います。ちょうど 2 文字でなければならず、識別関連なら `--`、非識別関連なら `..` です。ハイフン 1 つは `--` の短い書き方ではなく、単なる構文エラーです。
対処
多重度のあいだは `--` か `..` にします。
erDiagram
顧客 ||-o{ 注文 : "発注する"erDiagram
顧客 ||--o{ 注文 : "発注する"表示されるもの
描画はされるが、同じテーブルの箱が 2 つに分かれている
原因
表記ゆれです。実体名は文字列として完全一致で照合されるので、`顧客` と `お客様` と `カスタマー` は 3 つの別々のテーブルになります。英語なら大文字表記の慣習が「うっかり小文字で書いた」を目立たせてくれますが、日本語にはその安全網がありません。実測すると、`顧客` と `お客様` を使った図では箱が 4 つ描かれ、`顧客` に統一すると 3 つになりました。
対処
実体名の表記を最初に決めて、図のなかで一貫させます。論理名は日本語、物理名は英語と決めているなら、図ではどちらか一方だけを使ってください。
erDiagram
顧客 ||--o{ 注文 : "発注する"
お客様 ||--o{ 問合せ : "起票する"erDiagram
顧客 ||--o{ 注文 : "発注する"
顧客 ||--o{ 問合せ : "起票する"表示されるもの
多重度は描画されるが、意味が逆になっている
原因
それぞれの実体に近いほうの 2 文字がその実体のものだという規則は、逆に読み違えやすい形をしています。`顧客 ||--o{ 注文` は「1 人の顧客が 0 件以上の注文を持つ」です。これを `顧客 }o--|| 注文` にすると「すべての顧客はちょうど 1 件の注文に属する」と言ったことになり、意味を成さないまま何事もなく描画されます。
対処
真ん中から外に向かって読みます。顧客に接している記号は、注文の数ではなく顧客の数を表します。
erDiagram
顧客 }o--|| 注文 : "発注する"erDiagram
顧客 ||--o{ 注文 : "発注する"描画についての覚え書き
いずれもこのサイトが使う Mermaid 11.12.2 で実測したものです。
配置を決めるのは実体の数ではなく関連のかたち
実体が数珠つなぎに関連していると縦長の列になります。実測では 3 実体で viewBox がおよそ 116×470、40 実体で 116×7315 でした。ところが同じ 40 実体でも 1 つの中心テーブルに集まる形なら、はるかに横長で背の低い図になります。ここで扱う 6 種類のなかで唯一、大きさより「データの形」が絵の形を決める図です。収まらないスキーマは、描く数を減らすより、どの関連を描くかを変えるほうが効きます。
日本語には大文字表記という安全網がない
英語圏の慣習で実体名を大文字にするのは、`CUSTOMER` と `customer` が別の実体として黙って 2 つの箱になるからで、大文字で揃えておくと事故が目に見えます。日本語にはこの手が使えません。代わりに効くのは表記の統一だけです。送り仮名、カタカナか漢字か、`ID` か `id` か。図を書き始める前に決めておいてください。
文法は 6 種類のなかで最も厳格
関連ラベルは必須、属性の型も必須、多重度のトークンは閉じた集合です。ほとんど何でも描画できてしまい間違いが静かに通るガントと比べると、ER 図は早い段階で大きな声で失敗します。これは長所です。ER 図が描画されたなら、それが意図した図である見込みはかなり高いということです。
ラベルは HTML なので PNG 書き出しは描き直しになる
実体の属性表は SVG の `<foreignObject>` の中に描かれるため、ブラウザはこれを直接 canvas にラスタライズできません。このサイトの PNG 書き出しは以前これで静かに失敗し、SVG ファイルを返していました。現在は素の SVG テキストのラベルで描き直してから出力するので、正しく原寸の PNG が出ます。文字組みだけがごくわずかに異なります。
テーマは色を変えるだけで、レイアウトは変えない
同じソースを明るいテーマと暗いテーマで描画すると viewBox は完全に一致します。テーマを切り替えたせいで属性表が組み直されたり、列が切れたりすることはありません。
別の図が向いている場合
継承やインタフェース、メソッドを表したいなら、これは違う図です。ER にはそのどれも存在しません。クラス図を使い、そのかわり描いているのはテーブルではなくコードだと割り切ってください。
スキーマが大きい場合、全体を 1 枚の ER 図にすると誰も読まない壁の掛け図になります。いま説明したいことに関わる 5 テーブルだけを描いて、残りは省いてください。図は主張であって、目録ではありません。
そして本当の問いが「データがどう保存されているか」ではなく「システム間をどう流れるか」なら、システムごとにサブグラフを切ったフローチャートが答えになります。ER 図では答えられません。
他の図の種類
執筆 Dominik Malsch · 最終更新: