「このテーブル、どこに繋がってるんだっけ?」

「この user_id はどのテーブルの外部キーだろう?」「このテーブル、実はどこからも参照されていない?」——マイグレーションファイルやレビュー中のSQLを目で追ってリレーションを把握するのは、頭の中でパズルを組み立てるような作業です。

SQL to ER図 変換ツール は、CREATE TABLE 文を貼り付けるだけで、テーブル・カラム・主キー・外部キーの関係をMermaidのER図として即座に描画します。すべてブラウザ内で処理され、SQLは一歩も外に出ません。

SQL DDLからER図を自動生成する方法|CREATE TABLEを可視化

この記事では、ツールがどうやってDDLをパースしているかという実装の内側と、それゆえに知っておくべき対応範囲を解説します。

使い方

CREATE TABLE users (
  id BIGINT PRIMARY KEY,
  name VARCHAR(255) NOT NULL
);

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id BIGINT NOT NULL,
  total_amount INTEGER NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

これを貼り付けると、次のMermaid erDiagram コードが生成されます。

erDiagram
    users {
        BIGINT id PK
        VARCHAR name
    }
    orders {
        BIGINT id PK
        BIGINT user_id
        INTEGER total_amount
    }

    orders }|--|| users : "user_id -> id"

生成されたコードはGitHubのREADMEやPull Requestにそのまま貼り付ければ描画されます。

パースの仕組み:正規表現でDDLを分解する

パーサーはSQL専用の構文解析ライブラリを使わず、正規表現ベースの軽量パーサーSqlParser.parseDdl)で実装されています。処理の流れは3段階です。

① コメント除去とステートメント分割

const cleanSql = sql
    .replace(/--.*$/gm, '')           // 行コメント除去
    .replace(/\/\*[\s\S]*?\*\//g, '') // ブロックコメント除去
    .trim();

const statements = cleanSql.split(';').map(s => s.trim()).filter(Boolean);

; で単純分割しているため、カラムのデフォルト値に ; を含むような特殊なDDLには対応していません(実務ではほぼ発生しないケースです)。

② カラム定義を「括弧の外側のカンマ」で分割する

CREATE TABLE の本体をカンマで区切る際、素直に split(',') すると DECIMAL(10, 2) のような型定義の中のカンマまで割れてしまいます。そこで、括弧の深さを数えながら分割する専用関数を使っています。

private static splitByCommaOutsideParens(text: string): string[] {
    let depth = 0;
    // '(' で depth++, ')' で depth-- し、depth === 0 のカンマだけを区切りとして扱う
    for (let i = 0; i < text.length; i++) {
        if (text[i] === '(') depth++;
        else if (text[i] === ')') depth--;
        if (text[i] === ',' && depth === 0) { /* ここで分割 */ }
    }
}

これは JSON⇔CSV変換ツール のCSVパーサーで使った「状態を持つ1文字ずつの走査」と同じ発想です。SQLのカラム定義とCSVの引用符付きフィールドは、見た目は違えど「区切り文字が特定の状況下では無効になる」という性質が共通しています。

③ 各行を PRIMARY KEY / FOREIGN KEY / カラム定義に分類する

分割した各行を正規表現でパターンマッチし、3種類に振り分けます。

// テーブルレベルの主キー: PRIMARY KEY (id, tenant_id) のような複合キーにも対応
const pkMatch = trimmed.match(/PRIMARY KEY\s*\(([\s\w,`"]+)\)/i);

// テーブルレベルの外部キー
const fkMatch = trimmed.match(
    /FOREIGN KEY\s*\(([\s\w`"]+)\)\s*REFERENCES\s*(?:['\`"]?(\w+)['\`"]?\.)?['\`"]?(\w+)['\`"]?\s*\(([\s\w`"]+)\)/i
);

// カラム定義: `id BIGINT PRIMARY KEY` のようなインライン主キー・外部キーも解析
const colMatch = trimmed.match(/^['`"]?(\w+)['`"]?\s+(\w+(?:\([\w\s,]+\))?)(.*)$/i);

REFERENCES の正規表現は、カラム定義の末尾(インライン外部キー)とテーブルレベルの FOREIGN KEY 句の両方に対応しています。主キーは複合キーもサポートしており、PRIMARY KEY (id, tenant_id) のような定義は、該当する2カラムの両方に PK マークが付きます。

出力:Mermaidのカラス足記法

生成されるリレーション行は }|--|| というカラス足記法です。

orders }|--|| users : "user_id -> id"

}|(多)から ||(1)へ向かう矢印で、「複数の注文が1人のユーザーに属する」という1対多を表現しています。この記法の読み方や、他のパターン(1対1、多対多、識別/非識別関係)を体系的に知りたい場合は MermaidのER図記法リファレンス にまとめています。

なお、Mermaidの erDiagram はカラムの型に括弧を含められない仕様のため、VARCHAR(255) のような長さ指定は自動的に VARCHAR に短縮されます(type.replace(/\([^)]*\)/g, ''))。

対応していないDDLパターン

正規表現ベースの軽量パーサーゆえの制約もあります。SQLの構文解析器(パーサージェネレータ)を使わない設計は「バンドルサイズを抑えてブラウザで高速に動かす」ためのトレードオフで、次のパターンは認識されません。

パターン対応状況
CREATE TABLE 内の PRIMARY KEY / FOREIGN KEY(テーブル・カラムどちらのレベルも)✅ 対応
複合主キー PRIMARY KEY (a, b)✅ 対応
ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY❌ 非対応(CREATE TABLE 文の中に無いため)
CREATE TABLE IF NOT EXISTS✅ 対応
スキーマ修飾 schema.table_name✅ 対応(テーブル名部分のみ抽出)
-- 行コメント//* */ ブロックコメント✅ 除去してから解析

マイグレーションツールによっては、外部キーを別の ALTER TABLE 文で後付けするスタイルがあります(RailsのActiveRecordなど)。その場合、外部キーの行を CREATE TABLE の中に手動で移すか、該当する FOREIGN KEY (...) REFERENCES ... 部分だけを一時的に追記すると、リレーションを認識させられます。

ER図を確認するときのチェックポイント

  • 主キーが各テーブルに設定されているか
  • 外部キーの向きが意図通りか
  • 孤立しているテーブルがないか
  • 中間テーブルが多対多の関係を正しく表しているか

Pull Requestのレビューでは、SQL差分だけを見るよりもER図を添えたほうが影響範囲を共有しやすくなります。生成したMermaidコードをそのままレビューコメントに貼り付けられるのも、テキストベースで扱える利点です。

よくある質問

MySQLやPostgreSQLのDDLでも使えますか?

CREATE TABLE を中心とした一般的なDDLであれば、MySQLやPostgreSQLの定義確認に使えます。方言固有の型やオプション(ENGINE=InnoDB など)は無視され、テーブル・カラム・キー情報の抽出には影響しません。

外部キーがないSQLでもER図になりますか?

外部キー制約がない場合でも、テーブルとカラムの一覧として可視化できます。ただしリレーションの線は FOREIGN KEY / REFERENCES の情報を元に作られるため、関連を明確に出したい場合はDDLに含めてください。

ALTER TABLEで追加した外部キーは認識されますか?

現在のパーサーは CREATE TABLE 文の内部のみを解析するため、別の ALTER TABLE ... ADD CONSTRAINT 文で追加された外部キーは認識されません。認識させたい場合は、該当する FOREIGN KEY (...) REFERENCES ... の記述を一時的に CREATE TABLE 側に含めてから貼り付けてください。

生成した図はドキュメントに貼れますか?

はい。Mermaid形式で出力してGitHubのREADMEや設計ドキュメントに貼れば、コードに近い形で構成図を管理できます。カラス足記法の読み方は MermaidのER図記法リファレンス を参照してください。

まとめ

  • パースは正規表現ベースの軽量実装。括弧の深さを見てカンマを分割する処理が肝
  • PRIMARY KEY・FOREIGN KEY(テーブル/カラムどちらのレベルも)・複合主キーに対応
  • ALTER TABLE による後付け外部キーは非対応。マイグレーションのスタイルによっては手直しが必要
  • 生成コードはMermaidのカラス足記法。読み方は別記事のリファレンス参照

手元のSQLをそっとツールに預けて、見えていなかったテーブル間の関係を確認してみてください。