Tools mentioned in this article
Open the browser-based tool while you read and try the workflow immediately.
“¿Dónde estaba conectada esta tabla?”
“¿A qué tabla hace referencia este user_id?” “Un momento, ¿esta tabla no la referencia nadie?” — rastrear relaciones leyendo SQL en bruto es como armar un rompecabezas mentalmente.
El conversor de SQL a diagrama ER toma sentencias CREATE TABLE y renderiza al instante las tablas, columnas, claves primarias y foráneas como un diagrama ER de Mermaid. Todo se ejecuta en su navegador — su SQL nunca sale de él.

Este artículo explica cómo funciona realmente el analizador de DDL por dentro y, debido a cómo funciona, qué debería saber sobre su cobertura.
Uso
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)
);
Al pegar esto, obtiene este código Mermaid erDiagram:
erDiagram
users {
BIGINT id PK
VARCHAR name
}
orders {
BIGINT id PK
BIGINT user_id
INTEGER total_amount
}
orders }|--|| users : "user_id -> id"
Pegue el código generado directamente en un README de GitHub o en un pull request y se renderiza automáticamente.
Cómo funciona el analizador: descomposición del DDL con expresiones regulares
En lugar de una biblioteca completa de análisis SQL, la herramienta usa un analizador ligero basado en expresiones regulares (SqlParser.parseDdl). Funciona en tres etapas.
1. Eliminar comentarios y dividir en sentencias
const cleanSql = sql
.replace(/--.*$/gm, '') // elimina comentarios de línea
.replace(/\/\*[\s\S]*?\*\//g, '') // elimina comentarios de bloque
.trim();
const statements = cleanSql.split(';').map(s => s.trim()).filter(Boolean);
Como las sentencias se dividen ingenuamente por ;, un DDL con un punto y coma dentro de un valor por defecto no se analizará correctamente — un caso que en la práctica prácticamente nunca ocurre.
2. Dividir las definiciones de columna por comas fuera de paréntesis
Dividir ingenuamente el cuerpo de un CREATE TABLE por , también rompería en las comas dentro de definiciones de tipo como DECIMAL(10, 2). En su lugar, el analizador rastrea la profundidad de paréntesis y solo trata una coma como separador cuando la profundidad es cero.
private static splitByCommaOutsideParens(text: string): string[] {
let depth = 0;
// '(' incrementa depth, ')' lo decrementa; solo las comas en depth === 0 son separadores
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') depth++;
else if (text[i] === ')') depth--;
if (text[i] === ',' && depth === 0) { /* dividir aquí */ }
}
}
Es la misma idea que usa el analizador de CSV del conversor JSON⇔CSV — un recorrido carácter a carácter con estado. Las definiciones de columna SQL y los campos CSV entrecomillados se ven distintos en la superficie, pero comparten la propiedad de que “el delimitador deja de ser válido bajo ciertas condiciones”.
3. Clasificar cada línea como PRIMARY KEY, FOREIGN KEY o columna
Cada línea dividida se compara con patrones de expresión regular para clasificarla en una de tres categorías.
// clave primaria a nivel de tabla, incluyendo claves compuestas como PRIMARY KEY (id, tenant_id)
const pkMatch = trimmed.match(/PRIMARY KEY\s*\(([\s\w,`"]+)\)/i);
// clave foránea a nivel de tabla
const fkMatch = trimmed.match(
/FOREIGN KEY\s*\(([\s\w`"]+)\)\s*REFERENCES\s*(?:['\`"]?(\w+)['\`"]?\.)?['\`"]?(\w+)['\`"]?\s*\(([\s\w`"]+)\)/i
);
// definición de columna; también captura una cláusula REFERENCES en línea
const colMatch = trimmed.match(/^['`"]?(\w+)['`"]?\s+(\w+(?:\([\w\s,]+\))?)(.*)$/i);
El patrón REFERENCES coincide tanto con una clave foránea en línea al final de una definición de columna como con una cláusula FOREIGN KEY a nivel de tabla. Se admiten claves primarias compuestas — una definición como PRIMARY KEY (id, tenant_id) marca ambas columnas como PK.
Salida: notación de pata de gallo
Las líneas de relación que genera la herramienta usan notación de pata de gallo:
orders }|--|| users : "user_id -> id"
La flecha va de }| (muchos) a || (uno) — “muchos pedidos pertenecen a un usuario”, una relación uno a muchos. Para una guía completa de esta notación, incluyendo uno a uno, muchos a muchos y relaciones identificantes frente a no identificantes, consulte la Referencia de sintaxis de diagramas ER en Mermaid.
Tenga en cuenta que la sintaxis erDiagram de Mermaid no permite paréntesis en los tipos de columna, así que los especificadores de longitud se eliminan automáticamente — VARCHAR(255) se convierte en VARCHAR (type.replace(/\([^)]*\)/g, '')).
Patrones de DDL que el analizador no admite
Ser un analizador ligero basado en expresiones regulares en lugar de una gramática SQL completa — una decisión deliberada para mantener el paquete pequeño y rápido en el navegador — tiene límites:
| Patrón | Soporte |
|---|---|
PRIMARY KEY / FOREIGN KEY dentro de CREATE TABLE (a nivel de tabla o de columna) | ✅ Compatible |
Clave primaria compuesta PRIMARY KEY (a, b) | ✅ Compatible |
ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY | ❌ No compatible (está fuera de la sentencia CREATE TABLE) |
CREATE TABLE IF NOT EXISTS | ✅ Compatible |
Nombres calificados con esquema schema.table_name | ✅ Compatible (solo se extrae la parte del nombre de tabla) |
Comentarios de línea -- / de bloque /* */ | ✅ Se eliminan antes de analizar |
Algunas herramientas de migración añaden claves foráneas mediante una sentencia ALTER TABLE separada (ActiveRecord de Rails es un ejemplo común). Si ese es su caso, mueva temporalmente la línea de la clave foránea al cuerpo del CREATE TABLE, o añada la cláusula FOREIGN KEY (...) REFERENCES ... correspondiente antes de pegar, para que la relación se detecte.
Lista de verificación para revisar un diagrama generado
- ¿Tiene cada tabla una clave primaria configurada?
- ¿Son las direcciones de las claves foráneas las que pretendía?
- ¿Hay tablas huérfanas sin conexiones?
- ¿Representan correctamente las tablas intermedias las relaciones muchos a muchos?
En la revisión de pull requests, adjuntar un diagrama ER comunica el alcance de un cambio de esquema mucho mejor que el diff SQL en bruto por sí solo. Como la salida es texto plano (Mermaid), puede pegarla directamente en un comentario de revisión.
Preguntas frecuentes
¿Funciona con DDL de MySQL o PostgreSQL?
Sí, para DDL general centrado en CREATE TABLE. Los tipos y opciones específicos del dialecto (como ENGINE=InnoDB) simplemente se ignoran — no afectan la extracción de tablas, columnas ni claves.
¿Genera un diagrama aunque no haya claves foráneas?
Sí — obtendrá una lista de tablas y columnas. Pero las líneas de relación se derivan enteramente de las cláusulas FOREIGN KEY / REFERENCES, así que inclúyalas en su DDL si quiere que aparezcan relaciones.
¿Se detectan las claves foráneas añadidas mediante ALTER TABLE?
No. El analizador solo examina el interior de las sentencias CREATE TABLE, así que las claves foráneas añadidas después mediante una sentencia ALTER TABLE ... ADD CONSTRAINT separada no se reconocen. Mueva temporalmente la cláusula FOREIGN KEY (...) REFERENCES ... al cuerpo del CREATE TABLE si necesita que se refleje.
¿Puedo pegar el diagrama generado en documentación?
Sí. La salida de Mermaid se renderiza de forma nativa en READMEs de GitHub y en la mayoría de los visores de Markdown, así que puede gestionar su diagrama de esquema junto con su código. Consulte la Referencia de sintaxis de diagramas ER en Mermaid para saber cómo leer (y editar a mano) la notación de pata de gallo.
Resumen
- El análisis es una implementación ligera basada en expresiones regulares; el truco clave es dividir las comas solo fuera de los paréntesis
- Admite PRIMARY KEY y FOREIGN KEY tanto a nivel de tabla como de columna, incluyendo claves primarias compuestas
- Las claves foráneas añadidas después mediante
ALTER TABLEno se detectan — algunos estilos de migración necesitan ajuste manual - La salida usa la notación de pata de gallo de Mermaid; consulte el artículo de referencia complementario para saber cómo leerla
Entregue su SQL a la herramienta y vea relaciones que quizá se le habían pasado por alto.