Natural language to validated SQL
Text2SQL Analytics System
Turns natural-language questions into SQL with Google Gemini, then sanitizes, runs and caches the query against a normalized PostgreSQL schema. Includes connection pooling and audit trails.
Fig. 1 · From a question to rows
Synthetic data
Generated SQL (pre-computed)
SELECT c.city, SUM(o.total) AS revenue
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.placed_at >= '2026-03-01'
AND o.placed_at < '2026-04-01'
GROUP BY c.city
ORDER BY revenue DESC
LIMIT 3;Validation
- Single statement: passed
- Read-only (SELECT): passed
- Known tables and columns only: passed
- Row limit present: passed
Result (synthetic rows)
| city | revenue |
|---|---|
| Lakeport | 18,420.00 |
| Ashford | 15,075.50 |
| Brightwater | 12,960.25 |
Generated SQL (pre-computed)
SELECT COUNT(*) AS customers_without_orders
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL
LIMIT 1;Validation
- Single statement: passed
- Read-only (SELECT): passed
- Known tables and columns only: passed
- Row limit present: passed
Result (synthetic rows)
| customers_without_orders |
|---|
| 37 |
Generated SQL (pre-computed)
DELETE FROM orders
WHERE placed_at < '2024-01-01';Validation
- Single statement: passed
- Read-only (SELECT): failed
- Known tables and columns only: passed
- Row limit present: failed
Rejected
The query is refused before it reaches the database. Nothing is executed, and the attempt is the kind of event an audit trail exists to record.
54 / 54
core system tests passing
A 100% pass rate on the project's 54 core system tests. It covers that test suite. It isn't a proof that every question gets correct or safe SQL.
The idea
Most people who have a question about their data can’t write the SQL to answer it. A language model can write that SQL for them, but the generated query is untrusted input and has to be checked before it runs.
What I built
- Natural language to SQL with Google Gemini.
- Data normalization to 1NF, 2NF and 3NF, so the model queries a clean schema.
- SQL sanitization that checks generated queries before they run.
- Query caching, so a repeated question can skip generating the SQL again.
- Connection pooling to PostgreSQL.
- Audit trails.
Testing
The system passes all 54 core system tests. That’s what the tests cover. It doesn’t mean every generated query will be correct or that sanitization makes it impossible to misuse.
About the demo above
The walkthrough uses a small made-up schema and pre-computed outputs. Nothing calls a model or queries a database from this page. It shows how the pipeline works, including what happens when a request asks for something it shouldn’t.