Reportes SQL automáticos a Telegram con n8n
Cómo crear un workflow que consulta tu base de datos cada mañana, genera un resumen ejecutivo formateado y lo envía a un chat de Telegram o Microsoft Teams. Sin código adicional, sin servidores nuevos.
El escenario típico
Tienes una base de datos PostgreSQL — o MySQL, MSSQL, da igual — con métricas operativas. Puede ser un Contact Center, un sistema de ticketing, ventas, monitorización de infraestructura. Cada mañana alguien hace lo mismo:
- Entra a pgAdmin/DBeaver/SSMS
- Ejecuta una consulta guardada
- Copia los resultados a Excel
- Le da formato, pone colores, añade un comentario
- Lo envía por email o pega capturas en el grupo de WhatsApp del equipo
Ese ritual cuesta entre 15 y 30 minutos cada mañana. Por una persona. Todos los días laborables del año. Eso son entre 60 y 120 horas anuales que se gastan en mover datos de un sitio a otro. Y se automatiza en una mañana con n8n.
Qué vamos a construir
Un workflow que cada lunes-viernes a las 8:00 AM:
- Conecta a tu PostgreSQL y ejecuta una consulta de KPIs del día anterior
- Compara con la semana anterior para mostrar tendencia
- Formatea el resultado como tabla legible en Markdown
- Envía el mensaje al canal de Telegram (o Teams) del equipo
- Si algún KPI está fuera de umbral, marca el mensaje con alerta
Paso 1: Crear el bot de Telegram
Telegram facilita esto enormemente — no requiere registro de empresa, OAuth ni configuración compleja:
- Abre Telegram y busca
@BotFather - Envíale
/newboty sigue las instrucciones (nombre y username del bot) - BotFather te devuelve un token con formato
1234567890:ABCdefGHI...— guárdalo - Crea un grupo o canal nuevo (o usa uno existente del equipo)
- Añade el bot como miembro del grupo y dale permiso para enviar mensajes
- Envía cualquier mensaje en el grupo y luego visita:
https://api.telegram.org/bot{TU_TOKEN}/getUpdates - En la respuesta JSON, busca el
chat.iddel grupo — es un número negativo, ej:-1001234567890
Paso 2: Estructura del workflow en n8n
El workflow tiene cinco nodos. Los nombres entre corchetes son los tipos de nodo en n8n:
- [Schedule Trigger] — dispara el workflow lunes-viernes a las 08:00
- [Postgres] — ejecuta la query de KPIs
- [Postgres] — ejecuta una segunda query de comparativa semanal
- [Code] — formatea ambos resultados como mensaje Markdown
- [Telegram] — envía el mensaje al grupo
Paso 3: Schedule Trigger
Configuración del nodo Schedule:
Trigger Interval: Custom (Cron) Cron Expression: 0 8 * * 1-5 # minuto 0, hora 8, cualquier día, # cualquier mes, lunes a viernes Timezone: Europe/Madrid
Paso 4: La consulta SQL
Aquí va el ejemplo concreto que vamos a usar — un Contact Center que registra incidencias:
-- KPIs del día anterior, agrupados por prioridad SELECT prioridad, COUNT(*) AS total, COUNT(*) FILTER (WHERE estado = 'cerrado') AS cerrados, AVG(EXTRACT(EPOCH FROM (fecha_cierre - fecha_apertura))/60)::int AS mttr_min, COUNT(*) FILTER (WHERE mttr_min > sla_minutos) AS incumplidos FROM incidencias WHERE DATE(fecha_apertura) = CURRENT_DATE - INTERVAL '1 day' GROUP BY prioridad ORDER BY prioridad;
En el nodo Postgres de n8n, configúralo así:
- Operation: Execute Query
- Query: pega la consulta de arriba
- Credentials: crea unas con read-only sobre la base de datos — nunca uses credenciales con write para reportes
Paso 5: Formatear el mensaje (nodo Code)
Aquí está la parte más interesante. n8n permite ejecutar JavaScript en cualquier punto del workflow. Vamos a crear un mensaje con tabla formateada usando los caracteres monoespaciados que Telegram soporta entre triple backtick:
// Nodo Code en n8n — recibe los items del nodo Postgres const items = $input.all(); const hoy = new Date().toLocaleDateString('es-ES', { weekday: 'long', day: 'numeric', month: 'long' }); // Detectar si hay alertas de SLA const totalIncumplidos = items.reduce((acc, i) => acc + i.json.incumplidos, 0); const alerta = totalIncumplidos > 0 ? '🔴' : '✅'; // Construir el mensaje let msg = `${alerta} *Resumen Operativo* _${hoy}_ \`\`\` Pri | Total | Cerr | MTTR | SLA✗ ----+-------+------+------+----`; // Añadir cada fila for (const item of items) { const d = item.json; msg += `\n${d.prioridad.padEnd(3)} | ${String(d.total).padStart(5)} | ${String(d.cerrados).padStart(4)} | ${String(d.mttr_min).padStart(4)} | ${String(d.incumplidos).padStart(3)}`; } msg += '\n\`\`\`'; // Si hay incumplimientos, añadir nota if (totalIncumplidos > 0) { msg += `\n\n⚠️ *${totalIncumplidos} incidencias han incumplido SLA*. Revisar antes de las 10:00.`; } return [{ json: { text: msg, parse_mode: 'Markdown' } }];
Paso 6: Enviar a Telegram
Configuración del nodo Telegram:
- Resource: Message
- Operation: Send Text Message
- Chat ID: el ID del grupo (el número negativo de antes)
- Text:
{{ $json.text }} - Additional Fields → Parse Mode:
Markdown
Las credenciales del nodo Telegram son simplemente el token del bot que te dio BotFather.
Resultado en el grupo
Cada lunes-viernes a las 8:00 llega al grupo de Telegram un mensaje como este:
lunes, 5 de mayo Pri | Total | Cerr | MTTR | SLA✗ ----+-------+------+------+---- P1 | 3 | 3 | 18 | 0 P2 | 14 | 12 | 45 | 0 P3 | 27 | 24 | 95 | 0
O en un día con incidencias:
martes, 6 de mayo Pri | Total | Cerr | MTTR | SLA✗ ----+-------+------+------+---- P1 | 5 | 4 | 42 | 2 P2 | 18 | 15 | 78 | 3 P3 | 31 | 27 | 125 | 1 ⚠️ 6 incidencias han incumplido SLA. Revisar antes de las 10:00.
Variantes útiles
Comparativa con la semana anterior
Añade una segunda query Postgres con la misma estructura pero filtrando por CURRENT_DATE - INTERVAL '8 days'. En el nodo Code, calcula la diferencia y añade una flecha (↑/↓) al lado de cada KPI.
Adjuntar un Excel completo
Cambia el nodo Telegram por Send Document y añade antes un nodo Spreadsheet File que convierte el resultado SQL a XLSX. El equipo recibe el resumen en chat y el detalle como adjunto.
Solo enviar si hay alertas
Añade un nodo IF antes del Telegram con la condición totalIncumplidos > 0. Solo molestas al grupo cuando hay algo accionable.
Múltiples destinos
Para reportes diferentes a equipos diferentes — operaciones a un grupo, dirección a otro — duplica el nodo Telegram con configuraciones distintas, conectados al mismo nodo Code. n8n ejecuta ambos en paralelo.
El patrón aplica a cualquier fuente
Lo bonito de este workflow es que el patrón se reutiliza casi sin modificar para muchísimos casos:
- Reporte de ventas desde tu CRM — cambia la query, mismo formato
- Estado de servidores desde Prometheus o Zabbix vía API — cambia el nodo Postgres por HTTP Request
- Tickets de Jira/ServiceNow — usa el nodo nativo de Jira en lugar de SQL
- Métricas de Google Analytics — nodo GA4 nativo
- Alertas de Stripe — webhooks o nodo Stripe nativo
El núcleo siempre es el mismo: fuente de datos → transformación → mensajería. Una vez tienes el primero funcionando, el segundo lo montas en menos de una hora.
Lo que puede fallar y cómo prevenirlo
La conexión a la BD se cae
Activa la opción Continue on Fail en el nodo Postgres y añade una rama que envía un mensaje de error al grupo de operaciones. Mejor un "no pude generar el reporte" que silencio.
Datos en formato raro
Las fechas con timezone, los strings con caracteres especiales para Markdown, los números con muchos decimales — todos rompen el formato. En el nodo Code, sanea con String(), Number().toFixed(0) y escapando el _, *, [ en strings dinámicos.
Telegram trunca mensajes largos
El límite es 4096 caracteres por mensaje. Si tu reporte va a crecer, divídelo en varios mensajes o adjunta un documento.
¿Tu equipo aún copia-pega de pgAdmin?
Diseño e implemento workflows de reporting automatizado conectando tus bases de datos con Telegram, Teams, Slack o email. Plug-and-play en tu n8n existente.
Hablamos de tu caso →