You type "Show me MRR by plan for the last 6 months" into Fastero. The AI agent reads your schema, writes a SQL query, executes it against your database, and hands you a chart — with the SQL visible so you can verify every join and filter. No drag-and-drop, no schema memorization, no context-switching to a SQL editor. That's NL2SQL in practice.
This guide shows what happens between your question and the result, why schema awareness matters more than model choice, and where the technology still needs a human in the loop.
What happens between your question and the SQL?
Here's the actual pipeline. Not the marketing version.
┌─────────────────┐
│ Your question │
│ in English │
└────────┬────────┘
│
▼
┌─────────────────┐ ┌──────────────────────┐
│ Schema lookup │────▶│ Tables, columns, │
│ │ │ types, foreign keys │
└────────┬────────┘ └──────────────────────┘
│
▼
┌─────────────────┐ ┌──────────────────────┐
│ SQL generation │────▶│ Dialect-specific │
│ (LLM) │ │ query for your DB │
└────────┬────────┘ └──────────────────────┘
│
▼
┌─────────────────┐
│ Validation & │──── Syntax error? ──▶ Self-correct
│ execution │ and retry
└────────┬────────┘
│
▼
┌─────────────────┐
│ Result + chart │
│ + visible SQL │
└─────────────────┘Every step matters. Remove schema lookup and the model guesses at table names. Remove validation and syntax errors reach the user. The difference between tools that work and tools that don't is usually which stages they skip.
What does an actual NL2SQL interaction look like?
You connect a Postgres database with a typical SaaS schema and type:
"Show me MRR by plan for the last 6 months"
Fastero reads your schema, finds subscriptions with columns plan_name, amount_cents, status, and period_start, and generates:
SELECT
DATE_TRUNC('month', period_start) AS month,
plan_name,
SUM(amount_cents) / 100.0 AS mrr
FROM subscriptions
WHERE status = 'active'
AND period_start >= NOW() - INTERVAL '6 months'
GROUP BY 1, 2
ORDER BY 1, 2;The SQL is visible. You can read it, edit it, save it as a dashboard widget, or schedule it as a recurring report. The agent doesn't hide the query behind a "trust me" curtain.
A harder question: "Which customers downgraded last quarter and what were they paying before?"
SELECT
c.email,
prev.plan_name AS previous_plan,
prev.amount_cents / 100.0 AS previous_mrr,
curr.plan_name AS current_plan,
curr.amount_cents / 100.0 AS current_mrr,
prev.amount_cents / 100.0 - curr.amount_cents / 100.0 AS mrr_lost
FROM subscription_changes sc
JOIN customers c ON c.id = sc.customer_id
JOIN subscriptions prev ON prev.id = sc.previous_subscription_id
JOIN subscriptions curr ON curr.id = sc.new_subscription_id
WHERE sc.change_type = 'downgrade'
AND sc.changed_at >= DATE_TRUNC('quarter', NOW()) - INTERVAL '3 months'
AND sc.changed_at < DATE_TRUNC('quarter', NOW())
ORDER BY mrr_lost DESC;That's a three-table join with date arithmetic. The agent figured out the join path from foreign keys in your schema. This is also where you should read the SQL carefully: the join logic is correct if your subscription_changes table uses those foreign keys. If your schema models downgrades differently, edit the query. The point is you're editing, not writing from scratch.
Fastero
Connect your database. Ask questions. Get dashboards.
Postgres, BigQuery, Snowflake, and 10+ sources — live-connected, AI-powered, no dashboard builder learning curve.
Try free →Why does pasting your question into ChatGPT produce worse results?
You can paste "Show me MRR by plan for the last 6 months" into ChatGPT. You'll get syntactically correct SQL. It'll reference tables and columns that don't exist in your database.
Schema-aware (Fastero) Generic LLM (ChatGPT)
───────────────────── ──────────────────────
Table names: Reads from your DB Guesses ("billing"?)
Column names: Reads information_schema Guesses ("price"?)
Data types: Knows INT vs VARCHAR Assumes
Join paths: Follows foreign keys Infers (often wrong)
SQL dialect: Matches your DB engine Defaults to generic SQL
Result: Runs against your data You paste and debugChatGPT doesn't know your tables are called subscriptions (not billing), that the amount is stored in amount_cents (not price), or that plan names live in plan_name (not tier). It writes plausible SQL for a generic schema that doesn't match yours.
A generic LLM is great for SQL syntax help. "How do I write a window function" is a perfect ChatGPT question. But "show me revenue by channel" requires knowing your schema, and the model can't know what it can't see.
For a deeper look at how one-shot translation compares to agent-style reasoning, see what makes an AI data agent different from a chatbot.
How accurate is NL2SQL in practice?
Honest answer: it depends on what you're asking and how clean your schema is.
Single-table queries with clear column names hit 90%+ accuracy on a well-modeled schema. "Total revenue by month" works almost every time if your columns are named sensibly.
Multi-table joins are where accuracy drops. A three-table join with ambiguous foreign keys lands around 70-80%. The agent picks a join path, but whether it picks the right one depends on how explicit your schema's relationships are. Window functions (running totals, cohort retention, rank-within-group) are similarly unreliable across every NL2SQL tool in 2026, including ours.
Two things that actually move the needle:
Schema metadata. A column called rev_m gets misinterpreted. A column called revenue_monthly_cents with a description "Monthly revenue in cents, before refunds" gets interpreted correctly every time. Adding descriptions to your tables and columns is the single most effective thing you can do, and it's the thing everyone skips.
Glossary definitions. "Churn" isn't a column. It's a formula, and different teams compute it differently. Map your key business terms to exact SQL expressions and the agent resolves them consistently instead of improvising. Same discipline as defining metrics once as a single source of truth.
The queries that fail aren't random. They cluster around multi-condition, multi-join investigative queries. Show the SQL. Always.
How does Fastero's NL2SQL differ from other tools?
A few architectural choices that matter in practice:
Schema awareness from your actual database. Fastero reads tables, columns, types, and foreign keys directly from your connected sources: Postgres, MySQL, BigQuery, Snowflake, Redshift, and 20+ others. No manual schema file to maintain.
Multi-LLM and BYOK. You pick the model (OpenAI, Anthropic, or Gemini) and can bring your own API key. You're not locked into one provider or paying a markup on token costs.
Agent, not translator. Fastero runs a ReAct-loop agent with 80+ tools, not a one-shot text-to-SQL function. It inspects your schema, profiles data, writes queries, reads results, and decides what to do next. If a query errors, the agent reads the error message, adjusts, and retries. That recovery loop is the difference between a tool you abandon after one wrong answer and one that gets you to the result.
Visible, editable SQL. Every generated query is shown in full. Read it, edit it, save it to a dashboard, or schedule it. The SQL is a starting point you own, not a black box.
For a broader take on how this compares to traditional BI workflows, see when to stop dragging and start asking.
When should you still write SQL by hand?
NL2SQL is not a replacement for SQL fluency. Some jobs still call for handwritten queries.
Production pipelines. Generated SQL is for exploration and analysis, not for a job that runs at 3am and feeds your revenue dashboard. Write those queries by hand, version them, test them.
Performance-sensitive queries. The agent doesn't optimize for your indexes or partition strategy. A query that touches 100 million rows might work but run ten times slower than a hand-tuned version.
Complex edge-case logic. "Calculate net revenue excluding refunds issued more than 30 days after purchase, but only for customers who didn't receive a credit" has too many conditions for reliable one-shot generation. Break it into parts, generate each part, verify, assemble.
The sweet spot is ad-hoc analysis, quick exploration, and building the first draft of a query you then refine. NL2SQL replaces the 20 minutes of "which table is that in?" and "what's that column called?" — not the careful craftsmanship of a production query.
FAQ
Is NL2SQL safe to run against a production database? Fastero enforces SELECT-only queries from the natural language interface. No INSERT, UPDATE, or DELETE. It also injects automatic LIMIT clauses to prevent runaway result sets and runs cost estimation on BigQuery and Snowflake before execution. You should still use a read replica when possible, but the guardrails prevent accidental writes.
Can NL2SQL handle queries across multiple databases? Not in a single natural-language question. If your data lives in both Postgres and Snowflake, you'd first pull the relevant tables into Fastero's DuckDB store, then query across them with SQL. The NL2SQL layer works against whichever source you're connected to, one at a time.
How is this different from asking ChatGPT to write my SQL? ChatGPT doesn't see your schema. It guesses table and column names, defaults to generic SQL syntax, and can't execute the query to verify it works. Schema-aware NL2SQL reads your actual database structure, generates dialect-specific SQL, runs it, and returns real results. The output is a verified answer, not a template you paste and debug.
Does it work with NoSQL databases like MongoDB? Not directly. NL2SQL generates SQL, which requires a SQL-compatible engine. For MongoDB, you can use Fastero's connector to sync collections into the DuckDB store and query them with SQL from there.
What if the generated SQL is wrong? The SQL is always visible, so you can spot errors before acting on the results. Fastero's agent also self-corrects on execution failures: it reads the error, adjusts the query, and retries. For semantically wrong queries (correct syntax, wrong logic), your corrections feed back into the glossary so the same mistake doesn't repeat.
Try Fastero free — ask your database a question in plain English and see the SQL it writes. No credit card required.

