Abstract
Cada vez más equipos quieren consultar datos sin escribir SQL a mano. El problema es que un sistema Text-to-SQL no solo debe “traducir preguntas”, sino también entender el esquema, restringir permisos, validar consultas y explicar por qué una consulta es rápida o lenta. Ese enfoque coincide con la ruta propuesta por el tutorial oficial de LangChain para agentes SQL: listar tablas, inspeccionar esquemas, generar la consulta, revisarla, ejecutarla y corregir errores hasta obtener una respuesta; y el propio tutorial advierte que ejecutar SQL generado por modelos tiene riesgos y exige permisos mínimos. En paralelo, la documentación oficial de Python recomienda usar placeholders en sqlite3 para enlazar parámetros y evitar inyección SQL, mientras que la documentación de SQLite explica que EXPLAIN QUERY PLAN permite inspeccionar si una consulta hace SCAN, SEARCH y si usa índices.
SQL AI Sales Assistant
A safe Text-to-SQL demo that converts natural language business questions into SQL queries, executes them on a local SQLite retail database, and shows the generated SQL plus EXPLAIN QUERY PLAN.
This project was created as evidence for an article about SQL AI Database Solutions.
Topic
Talk to your database with AI: build a safe SQL query extractor with Streamlit and SQLite.
Features
- Natural language prompts such as
sales by month,top customers,sales in Lima. - Rule-assisted NL→SQL generation, designed to be transparent and auditable.
- SQLite demo database with customers, products, orders and order items.
- Read-only SQL validator that blocks destructive commands.
- Parameterized queries for user-provided filters.
- Streamlit interface.
- CLI demo for quick testing.
- Query plan inspection with
EXPLAIN QUERY PLAN.
Architecture
User question
↓
NL → SQL interpreter
↓
Read-only SQL validator
↓
SQLite execution
↓
Results + EXPLAIN QUERY…Cuerpo del artículo
La promesa de SQL + IA suena sencilla: le haces una pregunta al sistema y este devuelve una tabla, un indicador o una respuesta de negocio. Pero en la práctica, los sistemas serios no viven solo de “adivinar SQL”. Los benchmarks más influyentes lo dejan claro. Spider fue diseñado precisamente para medir si un modelo puede generalizar a bases de datos no vistas, y los resultados iniciales mostraron que el problema seguía siendo difícil incluso para consultas complejas. CoSQL, por su parte, añadió turnos conversacionales, aclaraciones y reformulaciones, algo mucho más parecido a lo que pasa en equipos reales cuando un analista pregunta, corrige y vuelve a preguntar.
Por eso, en vez de hacer un demo “mágico” y opaco, este proyecto usa una arquitectura híbrida y segura. El flujo es: el usuario escribe una pregunta en lenguaje natural, una capa de interpretación identifica la intención, se genera SQL, un validador bloquea sentencias peligrosas, SQLite ejecuta solo lecturas y la interfaz muestra tanto el resultado como el plan de ejecución. Esta decisión no es casual: LangChain documenta exactamente esa secuencia conceptual para un agente SQL y subraya que las credenciales del motor deben estar limitadas al mínimo necesario.
El caso de uso que elegí fue analítica de ventas retail, porque permite mostrar ejemplos de negocio que cualquiera entiende y, al mismo tiempo, obliga a tocar varios patrones SQL reales: agregaciones, JOIN, GROUP BY, filtros por ciudad, filtros temporales, rankings y cálculo de ticket promedio. También funciona muy bien con SQLite, que la documentación oficial de Python describe como una biblioteca ligera, basada en disco y sin proceso servidor separado, ideal para prototipos y aplicaciones pequeñas antes de migrar a motores mayores.
La base de datos del demo tiene cuatro tablas: customers, products, orders y order_items. Con ese esquema, ya puedes responder preguntas como estas:
¿Cuáles fueron las ventas por mes?
¿Quiénes son mis mejores clientes?
¿Qué productos son los más vendidos?
¿Qué artículos tienen stock bajo?
¿Cuánto vendí en Lima?
¿Cuál es el ticket promedio?
¿Cuánto se vendió en una categoría concreta?
¿Cuánto se vendió entre dos fechas?
Un ejemplo clásico es “Muéstrame las ventas por mes”. En ese caso, la capa NL2SQL detecta una intención temporal y genera esta consulta:
sql
Copiar
SELECT substr(o.order_date, 1, 7) AS month,
ROUND(SUM(oi.quantity * oi.unit_price), 2) AS revenue,
COUNT(DISTINCT o.order_id) AS total_orders
FROM orders o
JOIN order_items oi ON oi.order_id = o.order_id
GROUP BY substr(o.order_date, 1, 7)
ORDER BY month;
Ese ejemplo es importante porque muestra dos cosas. Primero, la IA no responde “en abstracto”, sino que aterriza en un SQL ejecutable. Segundo, el sistema puede explicar rendimiento. La documentación oficial de SQLite indica que EXPLAIN QUERY PLAN muestra si el motor realiza un SCAN completo o un SEARCH usando índices, y esa diferencia sirve para enseñar optimización de consultas con un caso real.
Otro ejemplo muy útil para negocio es el ranking de mejores clientes. Ahí usamos JOIN entre clientes, pedidos y detalle de pedido para sumar ingresos y contar órdenes. Esa es la consulta:
sql
Copiar
SELECT c.full_name,
c.city,
ROUND(SUM(oi.quantity * oi.unit_price), 2) AS total_sales,
COUNT(DISTINCT o.order_id) AS total_orders
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id
JOIN order_items oi ON oi.order_id = o.order_id
GROUP BY c.customer_id, c.full_name, c.city
ORDER BY total_sales DESC
LIMIT 5;
Este tipo de ejemplo es “real” porque responde una pregunta clásica de gerencia comercial: quién compra más, desde qué ciudad y con cuántos pedidos. En otras palabras, el sistema no es un juguete para seleccionar una sola tabla; trabaja con relaciones, agregaciones y límites, que son exactamente los componentes que un sistema Text-to-SQL serio debe manejar. Los trabajos sobre KaggleDBQA y sobre evaluación de ChatGPT en Text-to-SQL justamente remarcan que el salto desde datasets controlados a bases más reales sigue siendo un desafío, sobre todo cuando cambia el dominio, el formato y la forma en que los usuarios formulan sus preguntas.
La parte más importante del proyecto no está en la interfaz, sino en la seguridad. Si alguien te vende un “chat con tu base de datos” sin hablar de permisos, validación o inyección SQL, te está mostrando solo la mitad del sistema. La documentación de sqlite3 en Python recomienda expresamente usar placeholders como ? en vez de interpolar cadenas, para evitar ataques de inyección SQL. Mi demo sigue esa recomendación para filtros por ciudad, categoría o intervalos de fechas. Además, el motor bloquea cualquier consulta que no empiece por SELECT o WITH, y rechaza instrucciones como DROP, DELETE, UPDATE, ALTER, PRAGMA o múltiples sentencias encadenadas.
Aquí tienes el núcleo de esa validación:
python
Copiar
FORBIDDEN_SQL = {
"insert", "update", "delete", "drop", "alter", "attach", "detach",
"replace", "truncate", "create", "pragma", "vacuum", "reindex"
}
def validate_sql(sql: str) -> None:
normalized = re.sub(r"\s+", " ", sql.strip().lower())
if not (normalized.startswith("select") or normalized.startswith("with")):
raise ValueError("Solo se permiten consultas SELECT o WITH.")
for keyword in FORBIDDEN_SQL:
if re.search(rf"\b{re.escape(keyword)}\b", normalized):
raise ValueError(f"Consulta bloqueada por seguridad: contiene '{keyword}'.")
La interfaz la construí con Streamlit porque su guía oficial de inicio rápido está pensada precisamente para levantar una app de datos con muy poca fricción, instalando el entorno y creando una primera aplicación de forma directa. Para un demo académico, eso es ideal porque te deja concentrarte en el flujo NL2SQL y no en el frontend complejo.
La capa de interpretación también está diseñada para ser útil en clase o en una publicación técnica. En vez de esconder todo detrás de un LLM remoto, el sistema expone qué regla identificó, qué SQL generó, qué parámetros usó y qué plan de ejecución devolvió SQLite. Eso vuelve el comportamiento del demo auditado y explicable, que es justo lo que falta en muchos ejemplos de “IA para bases de datos”.
Este enfoque además se alinea con proyectos públicos del ecosistema. DB-GPT-Hub se presenta como un repositorio orientado a Text-to-SQL parsing with LLMs, con código, documentación, requisitos y experimentos para mejorar desempeño de modelos en Text-to-SQL. Vanna, por su parte, define su propuesta como “Natural language → SQL → Answers” y la documentación de Vanna 2.0 describe un framework de agente que conecta LLMs con bases de datos, aprendiendo de interacciones exitosas y aplicando controles de acceso. Para fines de artículo, eso permite mostrar que tu demo no sale de la nada: está alineado con líneas públicas y reconocibles del ecosistema.
La gran lección es esta: el verdadero valor de SQL + IA no está en reemplazar SQL, sino en encapsularlo de forma segura, comprensible y útil para el negocio. Un buen sistema Text-to-SQL no debe ser solo generativo; debe ser verificable. Si puede mostrar el SQL, justificar la consulta, enlazar parámetros, restringir permisos y enseñar el plan de ejecución, entonces deja de ser una demo vistosa y se convierte en una solución de ingeniería que sí puede escalar. Esa misma tensión entre potencia y fiabilidad es visible en la bibliografía reciente: los trabajos más sólidos siguen invirtiendo en schema linking, recuperación de ejemplos, validación y evaluación fuera de distribución, no solo en “usar un modelo más grande”.
Conclusión
Si quieres construir una solución de bases de datos con IA que de verdad sirva, empieza por un dominio concreto, un esquema pequeño pero real, una capa de validación estricta y una interfaz clara. Después de eso, puedes sustituir el motor híbrido por un LLM o por un framework especializado. Pero la base correcta sigue siendo la misma: esquema, seguridad, SQL verificable y observabilidad.
SQL AI Sales Assistant
A safe Text-to-SQL demo that converts natural language business questions into SQL queries, executes them on a local SQLite retail database, and shows the generated SQL plus EXPLAIN QUERY PLAN.
This project was created as evidence for an article about SQL AI Database Solutions.
Topic
Talk to your database with AI: build a safe SQL query extractor with Streamlit and SQLite.
Features
- Natural language prompts such as
sales by month,top customers,sales in Lima. - Rule-assisted NL→SQL generation, designed to be transparent and auditable.
- SQLite demo database with customers, products, orders and order items.
- Read-only SQL validator that blocks destructive commands.
- Parameterized queries for user-provided filters.
- Streamlit interface.
- CLI demo for quick testing.
- Query plan inspection with
EXPLAIN QUERY PLAN.
Architecture
User question
↓
NL → SQL interpreter
↓
Read-only SQL validator
↓
SQLite execution
↓
Results + EXPLAIN QUERY…
Top comments (1)
Student: Fabrizio Salvador Elias Perez Peralta
Important Observation: Moving from Regex to AST Validation
I would like to make an important observation regarding the security layer and the SQL validator proposed in the article.
The approach of using FORBIDDEN_SQL with regular expressions is an excellent first step to block destructive commands (such as DROP, DELETE, or UPDATE). However, from a strict security and vulnerability analysis perspective, relying on a "blacklist" via regex can be fragile. Attackers might use obfuscation techniques, or the LLM itself could generate unusual syntax under a prompt injection attack that manages to bypass plain-text filters.
A natural and much more robust evolution for this safe extractor would be to shift from text-based validation to AST (Abstract Syntax Tree) validation.
By using parsing libraries like sqlglot, we can break down the SQL query into its structural nodes and structurally guarantee that the root of the operation is strictly read-only, completely ignoring how the string is formatted. This eliminates the need to guess and block all possible variations of reserved keywords.
Real-world code example:
Here is how the original validate_sql function could be refactored to use AST, making it bulletproof:
This improvement maintains the hybrid and secure philosophy you proposed in the article, but elevates the SQL injection prevention to an enterprise-grade standard.