Back to Blog
NL to SQL AI analytics

Natural Language to SQL: Where It Works

Bence Kovács

Natural language to SQL has existed as an idea since the 1970s. Language models have changed its practical viability: non-technical users can describe a need in plain language and receive a working query often enough for the tool to be useful, not merely a party trick.

In practice, the capability handles a predictable set of questions well and breaks down in recognizable ways elsewhere. That distinction matters when building with it or evaluating it for a particular analytical task.

What the Capability Really Does

Natural language to SQL has three conceptual steps. First comes intent parsing: turning "how many users completed onboarding last month" into a structured request. That includes aggregation (count), subject (users), condition (completed onboarding), and time window (last month).

Next is schema mapping: matching those concepts to tables and columns in a particular database. "Users" may map to a users table; "completed onboarding" may be an events-table column or a user-profile status flag. "Last month" must resolve to date boundaries based on today's date.

The final step generates SQL the chosen database engine accepts, using the right dialect syntax and references to the selected tables and columns.

Every step can fail differently. Identifying the failing stage shows whether to rephrase the question, improve the schema, or accept that the request falls beyond the capability's reliable range.

Where It Works Well

NL to SQL is most dependable for retrieval from one table or a straightforward two-table join, with filters that clearly match column values and aggregations represented by standard SQL functions.

Examples include "How many users signed up in January 2026?", "What is the average number of queries per user in the Growth plan?", and "Which workspace accounts have more than five users?". Reliability comes from clear subject-verb-object phrasing, clean concept-to-column mappings, direct SQL aggregation equivalents, and unambiguous time expressions.

With consistent naming, meaningful columns, and table names that need no insider explanation, the tool can reliably handle more questions across two or three joined tables, moderate filters, and common window functions such as session analysis within a time gap.

Predictable Ways It Fails

Failures follow patterns rather than occurring randomly.

Ambiguous schema concepts. If your schema has three tables that could each plausibly be "users" depending on context (a users table for account holders, a members table for workspace members, and a contacts table for people who have not yet created an account), the model will have to guess which one you mean. Sometimes it guesses right. Sometimes it does not. The question "how many users do we have?" has three possible answers and the model cannot resolve the ambiguity from the question alone.

Business definitions may exist outside the schema. "Active users" could mean people who ran at least one query in the last 30 days, but that meaning is unavailable unless encoded in a view or computed column. Without it, the model must infer the definition, sometimes correctly, or request clarification.

Multi-hop joins add intermediate tables. "What percentage of accounts that connected BigQuery as their data source ran at least one query within 48 hours?" involves accounts, data source connections, and query events, plus a time comparison between event types. SQL can express it, but the wording says little about the join path, tables, or keys. Failure is meaningfully more common here than in single-table aggregations.

Relative time can be unclear. "Last month" is specific, but "recent" and "since we launched the new feature" depend on missing context. "In Q1" is generally clear only after deciding between fiscal Q1 and calendar Q1.

The Query-Shown Principle

That is why Mitzuo always displays the generated query with the result. Ask "how many active users do we have?" and you can see if active means logging in during the last 7 days. If you meant users who ran a query in the last 30 days, the mismatch is immediately visible, letting you refine the question or edit the query.

A result without its query cannot be verified without manually repeating the analysis. Showing the query lets you inspect the logic in 30 seconds and judge whether it answered the intended question.

This does not eliminate the failures above. It exposes them instead of hiding them. A wrong result that appears correct is more dangerous than one you can recognize as wrong. Query transparency turns silent failures into visible failures.

Making a Schema NL-Friendly

The difference between handling simple questions and handling most real questions is partly a schema issue, not solely a model issue. Consistent naming and meaningful columns, as discussed in our earlier post, also improve how reliably NL to SQL tools work.

The most impactful changes for NL-friendliness: use human-readable column names (not usr_act_dt but activated_at), encode business definitions as views when they are stable enough (create a v_active_users view that defines active so the model can reference it), and document your most common business terms in a schema metadata layer that the model has access to at query time.

No schema surgery is needed. These additive changes leave the existing schema intact while making question-to-query mapping more deterministic.

Where It Does Not Replace Analytical Thinking

NL to SQL retrieves data, but it does not interpret it. A model can query 30-day retention by cohort, yet cannot judge whether the rate is good, whether its trend matters, or which product changes caused it. Those judgments depend on your product and market context.

Complex attribution, multi-touch conversion analysis, and churn prediction modeling work the same way. They need analytical design before SQL. The model can turn a defined design into code, but it cannot replace designing the analysis.

The capability is best understood as a translation layer: it removes the mechanical task of converting a clear question into valid SQL and shortens the path from "I have a question" to "I have the data." It does not replace forming the question or interpreting the result. Those remain human tasks, where much of the analytical value is created.

More from the blog