Teverant AI · Insights

2026-09-07

Text2SQL in practice: how enterprises can query data in natural language

From scoping and a metrics semantic layer to access isolation and SQL validation, this article systematically breaks down practical methods for Text2SQL, helping enterprises implement natural-language data queries in a secure, controllable way.

1. Set the boundaries first: don't start the pilot with "query anything"

A Text2SQL pilot should first establish which questions the system is allowed to answer, rather than chasing how many phrasings it can cover. Two variables determine the boundaries: how complex the query itself is, and how much damage a wrong answer would do. The public BIRD-CRITIC evaluation shows that current models still struggle to remain stable when multi-table reasoning, complex constraints, and deep nesting are involved. Complexity therefore can't all be left for the model to digest: logic whose joins can be simplified through data modeling, or whose calculations can be fixed in place through ETL, should be handled on the data side first.

The initial scope should be narrowed to a single business subject: the relationships between tables are already fixed, metric definitions are not in dispute, queries mainly involve filtering, aggregate statistics, and grouping by dimension, and only reads are allowed. Cross-subject data attribution, analyses that require multiple layers of subqueries, and calculations that directly affect settlement results can remain under human review rather than entering the scope of automatic execution. This isn't lowering the bar; it separates model variables from data governance issues, so that if the pilot fails, you can still tell whether the error lay in semantics, data, or SQL.

You also need to distinguish between types of users first. Analysts can read and modify SQL, so for them the system can be positioned as a coding assistant: it generates drafts and shows the objects referenced, and users check them before executing. Business staff usually see only the final number and can't spot a wrong join, a missing filter, or an aggregation-level error, so they need stricter entry conditions. Such entry points should be bound to governed datasets, with limits on the metrics, dimensions, and time ranges that can be asked about. The two modes can't share the same acceptance thresholds.

Risk levelTypical scopePilot handling
LowMetric queries that match existing business dashboards, fixed-dimension summaries, trend comparisonsCan execute automatically after passing validation
MediumA few stable joins, filter conditions that need to be supplied, or metric meanings that may be ambiguousClarify first; have an analyst confirm when necessary
HighBulk retrieval of detailed records, selecting sensitive subjects, crossing tenant boundaries, feeding into financial accountingBlock automatic execution by default and route to a controlled process

An allowlist should describe "what may be queried," not just maintain a set of banned words. Each scenario needs to be bound to the data objects it can access, the metrics and dimensions it supports, the permitted query shapes, the result granularity, and how exceptions are handled. Otherwise, after the data structure changes, the same natural-language sentence may generate SQL that is syntactically correct but whose business meaning has drifted.

Pilot acceptance can't stop at "was SQL successfully generated" either. At a minimum, record separately: whether executing the statement produced the correct result, whether the output followed the established business definitions, whether the system proactively asked follow-up questions on ambiguous questions, whether it refused out-of-scope requests, whether end-to-end response time was acceptable, and how many requests ultimately required human handling. The generation rate only shows that the pipeline runs; it doesn't prove the system is fit to open up to the business.

Once the boundaries are set, the team should produce a reviewable list of scenarios: which questions are answered automatically, which require additional conditions, which only generate drafts, and which are always refused. Subsequent expansion should open things up item by item based on evaluation results, rather than broadening capabilities all at once by modifying the prompt.

2. Metric definitions come before prompts: build a searchable semantic layer

The first problem enterprise data querying usually exposes is not SQL syntax but business terms that lack a single interpretation. Given an orders table, a payments table, and a revenue detail table, a model can write an executable "sales" query against each, but the fact that the database can run it doesn't mean the result matches the business's definition. The prompt therefore shouldn't be responsible for defining metrics; the definitions must first be organized into semantic assets that machines can search, execute, and trace.

The metrics catalog is the entry point to the semantic layer. Each metric entry needs to describe its business meaning, standard name, calculation expression, applicable dimensions, default period, prerequisite filters, owner, version status, and effective period. It can't just store a paragraph of description; it must also specify the data source, aggregation method, time field, deduplication rules, and null handling. Otherwise, even if retrieval finds the metric, the generation stage still has to guess the actual calculation.

ObjectWhat needs to be fixedRuntime use
MetricDefinition, formula, reporting period, qualifying conditions, versionConstrains calculation logic
DimensionHierarchy, allowed range, codes and display namesControls grouping and drill-down
Data relationshipsSource fields, join keys, cardinality, and valid periodsRestricts join paths
TermsAliases, departmental jargon, pinyin forms, common misspellingsImproves question matching

Names like "new customers" and "active users" often have both a group-level definition and a department-level definition. From an engineering standpoint, give each standard definition a stable identifier, then attach departmental variants and natural-language aliases to the corresponding version. If a user's question matches multiple valid definitions, the system should return the candidates and ask which department's statistics, time range, or business scope is meant. Letting the model choose on its own based on context disguises a definitional conflict as a normal-looking number.

The semantic layer also needs to reach down to the execution side. Reviewed metric logic can be published as constrained query templates, semantic models, or a unified metrics API. The model only parses the metric, the dimensions to view it by, the conditions, the period, and the sorting requirements the user asked for; a deterministic component then assembles the query. Complex calculations, fixed filters, and standard joins are no longer generated on the fly, and during an audit you can trace which version of a definition a result used.

The goal of schema linking is not to stuff the entire database structure into the context but to narrow the model's range of choices. A single request can first retrieve the relevant metrics and then expand to the necessary fact data, dimension data, field descriptions, join keys, and candidate enumerated values. The structure fed to the model should be limited to the subgraph needed for that query, while preserving join directions and field semantics, so that the model doesn't build wrong joins based merely on similar physical names.

Chinese-language retrieval needs to handle term understanding and value matching separately. Enterprise abbreviations, business synonyms, and field comments are suited to semantic retrieval; for specific values such as organization names, region names, and product names, you can build character, pinyin, and fuzzy-matching channels in parallel and then rerank the candidates. Common typos, homophone input errors, and keyboard slips shouldn't be handed to the large language model (LLM) to guess at; instead, the retrieval layer should produce candidate values that can be verified.

  • Single match: carry the metric version and the relevant schema into query planning.
  • Multiple definitions matched: show the differences, and generate SQL only after clarification.
  • Terms matched but no metric located: return the conditions that were recognized and prompt the user to specify the business scope.
  • No reliable match: stop generating, to avoid inferring business meaning from physical table names.

The acceptance focus for this layer is not whether the model "understood" the terms, but whether the same question can be consistently bound to a definite metric version, join path, and filter rules. Only when these decisions can be recorded and reproduced does subsequent SQL validation have a clear basis.

3. Access isolation: the model being able to generate a query doesn't mean the user is authorized to run it

The permission boundaries of Text2SQL can't be built on prompts. A model can fill in table names, join conditions, and filter expressions on request, but it is not an authentication component, nor should it take part in authorization decisions. If a user writes "I'm the head of finance" in a question, that can only be treated as query text; the person's real identity, organization, business role, tenant scope, and purpose of access should come from the login session, an identity service, or an approval system, and be passed into the query pipeline as context that conversation content cannot override.

Once trusted context enters the system, the permission decision should be made first, and only then should generated results be allowed to execute. Even if the model leaves out a department condition, underlying controls must still prevent cross-department reads; even if a generated statement references sensitive columns, the execution side must refuse it or handle it according to the rules. In other words, authorization constraints must live in deterministic components, rather than relying on the model to assemble the WHERE clause correctly every time.

Control pointAppropriate responsibilitiesPractices not to rely on
Semantic layerRestrict the available metrics, dimensions, data objects, and drill-down scopeHanding the entire schema to the model and then trying to remediate
Query gatewayVerify the requesting principal; constrain result size, export methods, and query costAllowing access based on identity claims in the user's natural language
DatabaseEnforce row-level policies, column-level authorization, controlled views, and read-only permissionsRelying solely on prompts to forbid access to sensitive data

Permission design needs to cover objects, records, fields, and result delivery. Object scope is narrowed through lists of databases, tables, or views; record scope is forcibly trimmed by tenant, organization, or data ownership; field scope controls whether sensitive columns are visible, hiding or transforming their content according to policy; and result delivery constrains result size, file downloads, and bulk exports. The key here is not to add one more check but to ensure that no single point of failure directly widens the scope of visible data.

The generation component and the execution component should also be isolated. The model side only produces candidate queries and never touches credentials that can connect directly to data sources; the execution service uses a dedicated restricted account that exposes only the necessary read capabilities. Creating tables, altering schemas, writing, deleting, calling stored procedures, and unnecessary dangerous functions should be disabled in account permissions and gateway rules, not merely intercepted by string matching. Data access can go through a query gateway, an isolated environment, or a read replica, so that generation errors and malicious input cannot directly affect the production write path.

Read-only doesn't mean low risk. A perfectly legitimate SELECT can still read too many detailed records, bypass tenant scope, or consume large amounts of resources through complex calculations. So before execution, you also need to check the referenced objects, permission policies, and query structure; during execution, apply timeouts, resource quotas, and result-size limits; and when a download is needed, authorize it separately. Input checks and SQL injection protection are baseline measures; they can't replace a complete permission model.

Audit records should span the entire request, not just store the final SQL. Traceable information includes the original question, the principal attributes supplied by the authentication system, the metadata retrieved, the candidate statements and their revision history, authorization decisions, execution status, a summary of the results, and any view or export actions. The logs shouldn't expose full sensitive results a second time, but they must be able to answer: who requested which data in what context, on what rules the system allowed or blocked it, and where the results ultimately went.

When accepting access isolation, don't test only normal queries. Also cover cases such as forged identities, cross-tenant questions, attempts to lure the system into accessing unauthorized tables, requests for sensitive fields, excessive exports of detailed records, and using complex SQL to get around restrictions. The pass criterion is not that the model "usually refuses," but that the deterministic execution boundaries hold no matter what the model generates.

4. The generation pipeline: turning a one-shot answer into a controllable engineering pipeline

Enterprise Text2SQL shouldn't cram requirement understanding, table selection, SQL writing, and error fixing all into a single prompt. That keeps the pipeline short, but the intermediate decisions are invisible: once a result is wrong, it's hard to tell whether the problem lies in business semantics, table relationships, or the SQL expression. A more controllable approach is to break generation into several steps, each with well-defined inputs and outputs.

StepMain taskIntermediate output
Request classificationDetermine whether the user is looking up detailed records, viewing a summary, making a comparison, or asking a question the data can't answerQuery type and processing path
Semantic disambiguationIdentify multiple possible interpretations of metric names, time expressions, and business objectsConfirmed semantics, or questions awaiting user input
Semantic retrievalExtract the relevant tables, fields, and relationships from metric definitions and the schemaA restricted candidate data scope
Query planningOrganize the metrics, grouping dimensions, constraints, time range, aggregation logic, and table join routeA structured plan or AST
Dialect compilationConvert the intermediate representation into SQL the target database can executeCandidate SQL
Rule checkingCheck whether the generated result conforms to the plan and the execution constraintsPass, reject, or revision feedback
Controlled executionCall database tools and collect results or error messagesResult set, execution status, or error
Result explanationOrganize the output around the original question, stating the conditions and statistical scope actually usedA user-facing answer

The most critical isolation layer among these is the query plan. The model shouldn't jump directly from natural language to final SQL; it should first submit a machine-readable intermediate representation—for example, placing the "subject of the statistic," "grouping fields," "predicate conditions," "date boundaries," "aggregation operators," and "join relationships" into fixed fields. A downstream component then compiles it into the dialect required by MySQL, PostgreSQL, or the data warehouse. This way, business semantics and database syntax are handled separately: when table names or function syntax change, there's no need to reinterpret user intent; and when errors occur, you can pinpoint whether the plan itself is wrong or the compiled output deviated from the plan.

Not all generation needs to be left to the model. For queries with a stable structure and a limited set of parameters, prefer matching query templates or parameterized SQL. The model is responsible only for extracting parameters such as dates, regions, and products and for choosing the applicable template. Only questions that require ad hoc combinations of dimensions or cross-table exploration, and that templates can't cover, go down the free-generation path. The two paths should be split explicitly, rather than having the model reassemble the complete statement every time.

An agent is suited to tasks that require multi-step tool calls, such as screening candidate tables, reading the necessary schema, reviewing candidate statements, revising based on database errors, or issuing follow-up queries as needed. But it can't be given autonomy to loop indefinitely. The runtime configuration should enforce at least the following boundaries:

  • allow calls only to approved retrieval, checking, and query tools;
  • limit the number of tool steps a single task can take;
  • limit the number of revisions the same error can trigger;
  • set a single execution resource budget for the entire task.

After the database returns an error, the candidate SQL and the error content can be sent to a revision step to handle generation problems such as identifier quoting, field types, or object names. But revisions must go through the checks again rather than executing the modified statement directly. The goal of the whole pipeline is not to add steps but to ensure that every transformation produces an artifact that can be checked, so that templates, the model, and the agent each take on work with clear boundaries.

5. SQL validation: from "it runs" to "provably trustworthy"

A database accepting a SQL statement only shows that it is syntactically valid and that the objects it references exist; it doesn't prove that the query is safe, that the business definition is correct, or that resource consumption is reasonable. Enterprise data querying needs to break validation into pre-execution static checks, business semantic verification, cost control, and post-execution result checks, with an auditable verdict preserved for each step.

Parse the structure first; don't check strings directly

The execution service should parse the SQL into an abstract syntax tree according to the target database dialect, and then check the statement type, referenced objects, expressions, and join relationships. Simply searching for keywords like DELETE and DROP is easily defeated by comments, capitalization, nested expressions, or dialect differences, and it can't detect risks hidden in functions and subqueries.

  • Statement scope: allow only read-only SELECT; reject multiple statements and any data definition, data modification, or permission change operations.
  • Object scope: tables, views, fields, and functions must be on the authorized list, and wildcard fields must be expanded and checked one by one.
  • Structural risks: identify multi-table queries without join conditions, suspicious join keys, conditions not propagated to joined tables, and JOINs that could blow up the result set.
  • Scan risks: check whether detail queries lack necessary time or tenant constraints, and whether there is unbounded sorting, a tendency toward full table scans, or overly broad column projection.
  • Bypass risks: reject comment obfuscation, dangerous functions, dynamic SQL, external access capabilities, and statements that can't be parsed reliably.

SQL that can't be parsed shouldn't be executed with its flaws intact. Rather than guessing at the risks with string rules, send it back to the generation step to be rebuilt, or route it to human handling.

Once the syntax passes, verify the business semantics

The more insidious problem is usually not a SQL error but results that look reasonable while using the wrong definition. The validator needs to compare the query plan item by item against the metric definitions in the semantic layer: Does the calculation expression match? Is it using the time the business event occurred or the time the data was written? Is the aggregation level right for the question? Is the deduplication key correct? Are currency handling and the business time zone consistent?

Multi-table queries also require verifying the join path. When a fact table is joined to a dimension table, a wrong key or incomplete filter conditions can change the row count; when a one-to-many relationship takes part in aggregation, you need to confirm whether the aggregation happens before or after the join. If the user's question is ambiguous about the time range, organizational scope, or metric definition, clarify first rather than relying on the model to fill in the gaps on its own.

Put the resource budget before execution

After the static and semantic checks pass, evaluate the query using EXPLAIN, the optimizer's estimates, or cost information provided by the data platform. The execution policy should constrain the estimated scan size, number of result rows, runtime, and concurrency usage together. When a query exceeds the budget, you can narrow the time range, reduce the returned fields, or switch to a pre-aggregated query; tasks that still can't be brought within budget are moved to asynchronous processing or refused.

Check stageMain inputsOutput evidence
Structural checkSQL abstract syntax tree, list of authorized objectsStatement type, object references, join risks
Semantic checkQuery plan, metric definitions, data modelDefinition match results and ambiguities
Cost checkExecution plan, resource budgetAllow, rewrite, run asynchronously, or refuse
Result checkQuery results, aggregation relationships, historical baselinesAnomaly flags and explanatory information

Successful execution doesn't mean validation is over

After results come back, you still need to check for empty sets, deviations in order of magnitude, abnormal year-over-year changes, and cases where line items don't reconcile with the total. When an anomaly is found, distinguish between "the data really is like this" and "the query may be wrong": the former comes with a notice, while the latter blocks a direct answer and enters the correction process. Execution errors can send the SQL and the error message back to the correction step, but retries must be limited, to avoid repeatedly generating near-identical statements that keep consuming database resources.

The final presentation shouldn't be just a number. At a minimum, it should state the metric definition used, the filter conditions actually applied, the reporting time range, and the data cutoff time; where necessary, add the source tables, join methods, and aggregation logic. The goal here is not to dump the full SQL on the user but to make the results reviewable and ensure that the security, semantic, and cost decisions are all on record.

6. Failure fallbacks: be explicit about when to clarify, retry, degrade, or hand off to a person

Fallback handling in Text2SQL can't be reduced across the board to "Generation failed, please try again." Different failures call for different actions: when information is missing, ask for the conditions; when definitions conflict, let the user choose; terminate unauthorized requests outright; send only syntax problems to repair; switch to a lower-cost path when resource consumption is unacceptable; and stop answering when the results aren't trustworthy enough. Classify the failure first, then decide whether to continue, so that the model doesn't keep rewriting SQL while the cause is still unknown.

Failure typeDetection signalSystem action
Missing semanticsNo reporting period, object scope, or aggregation levelAsk structured follow-up questions; don't generate executable SQL
Ambiguous definitionA single business term matches multiple metric definitionsShow the candidate definitions and their differences; wait for the user to confirm
Permission restrictedThe target fields, rows, or level of detail exceed the user's authorizationRefuse clearly; don't get around the policy by rewriting the query
Fixable errorObject names, quotation marks, field types, or dialect incompatibilitiesRevise within a controlled number of attempts and rerun the full validation
Resource riskExecution timeout or failed cost checkNarrow the scope, lower the granularity, or fall back to existing aggregated results
Anomalous resultNull values returned, contradictory aggregation relationships, or clearly abnormal resultsHold off on answering directly; keep diagnostic information for review

The clarification step should present a limited set of options rather than continuing with open-ended guesses—for example, asking the user to confirm which metric definition to use, to choose between the calendar month and a custom date range, to limit the organizational scope, and to decide whether results should be returned by day, week, or month, or as detailed records. The dialogue module is responsible only for collecting the missing parameters; the execution module shouldn't be called until the parameters are complete. This prevents the same model from filling in assumptions and writing those assumptions into the query at the same time.

Candidate definitions need to show the differences that determine the result, not just list a few similar names. The system can explain the time field, filter conditions, and aggregation method behind each candidate, so that the user makes the business choice. If the system applies a default, it should also list it explicitly before the results rather than hiding default conditions inside the SQL.

The scope of automatic repair must be kept narrow. What machines are suited to handle are technical, localized, and verifiable problems, such as failures to resolve a column name, string quoting that doesn't meet the target database's requirements, type mismatches between the two sides of a comparison, or generated syntax that doesn't match the actual database dialect. Conflicting metric definitions, uncertain join relationships, authorization failures, and anomalous results are not syntax fixes and shouldn't be left to a repair loop to guess at.

Every round of revision should be treated as a new query: recheck the user's permissions and data scope, rerun syntax and object validation, and then reassess scan cost, result size, and runtime limits. The system also needs a fixed retry limit; once it's reached, exit immediately, rather than looping indefinitely because the error message changes. Repair records should retain the original SQL, an error summary, the changes made, and the final status to support later diagnosis.

Degrading doesn't mean returning a less precise number without saying so. Workable approaches include narrowing the time range, reducing dimensions, switching to an authorized aggregation level, or generating only a query plan for human confirmation. Any degradation must be explained to the user, stating which conditions were adjusted; if an adjustment would change the business meaning, it must be confirmed again.

The final fallback still needs to offer a next step. At a minimum, the output should state whether the failure is a semantic, permission, execution, or result-validation problem, list the metric, time, organization, and granularity conditions that were recognized, and provide question templates the user can select or rewrite directly. When human intervention is needed, hand over the original question, the structured query plan, the candidate SQL, the validation conclusions, and the execution errors together, so that data analysts don't have to repeat the investigation.

7. From pilot to launch: advance with evaluation sets, shadow traffic, and phased rollout

Launching Text2SQL shouldn't hinge on whether demo cases succeed; you need to verify that the system is stable under real questions, permission constraints, and abnormal input. Evaluation data can be compiled from historical data-request tickets, BI search logs, and SQL written by analysts, with sensitive information removed. Samples need to cover common queries, paraphrases, incomplete expressions, unauthorized requests, multi-table joins, empty results, wrong fields, and similar cases.

Each sample should record the user's question, the authorized identity, the expected definition, the reference result, and the data scope the user may access. The reference answer shouldn't be just a single SQL statement, because different formulations can yield the same result; metric owners should confirm the business definitions, and analysts should verify join paths, filter conditions, and aggregation methods. New problems found in production should keep being added to the evaluation set, making it the regression baseline for subsequent changes.

Can Text2SQL connect directly to a production database?

During the pilot, statements generated by the model shouldn't go straight into the production execution path. Before launch, you can first run in shadow mode: the system receives real requests and generates candidate SQL, but the results aren't returned to users. If results need to be verified, execute them in a controlled read-only environment and have analysts compare them against existing reports or confirmed queries.

Once shadow validation passes, open access gradually by business department, data subject, and risk level. Within the scope of the phased rollout, you still need to keep read-only permissions, query quotas, audit records, and a manual kill switch. Assisting analysts in writing SQL and returning answers automatically to business staff carry different accuracy requirements and can't use the same release criteria.

If the SQL executes successfully, does that mean the answer is correct?

No. The database accepting the syntax only shows that the statement can run; it can't prove that the metric definition, time field, join relationships, or permission scope are correct. Offline evaluation should look at different issues separately, including whether queries execute correctly, whether results match the reference data, whether the business definition is hit, whether unauthorized requests are blocked, and whether dangerous statements are wrongly allowed through.

Nor should an exact match of the SQL string be used as the main criterion. Differences in column order, aliases, subqueries, and join syntax can still produce the same result. Evaluation should combine structural checks, result comparison, and definition review; where empty results are involved, you also need to distinguish between "there genuinely is no data for the business" and "the filter or join conditions were written wrong."

Faced with a vague question like "How are sales doing?", should the system guess or ask?

When the missing conditions would change the business conclusion, it should ask rather than guess. The evaluation set needs to include ambiguous samples specifically, to check whether the system can recognize a missing time range, organizational scope, statistical definition, or comparison baseline. Records of users supplying conditions, choosing clarification options, and rewriting questions should all feed into subsequent regression tests.

If the missing information doesn't affect the result, or the semantic layer already has a confirmed default rule, execution can proceed, but the answer should clearly show the conditions that were applied. Whether the system needs to ask a follow-up question should be determined by the definition rules, not by the model's ad hoc inference.

How should an enterprise judge whether Text2SQL is ready for launch?

Launch criteria should be set separately according to scenario risk, rather than looking at a single overall accuracy figure. The team needs to set separate thresholds for result correctness, conformance to definitions, permission blocking, and control of dangerous statements; a high-risk subject that fails can stay closed even if other subjects have already been opened.

Once in production, keep collecting user rewrites, clarification choices, ratings and feedback, failure classifications, and SQL corrected by analysts. Whenever the model version, prompts, semantic layer, or permission policies change, replay the fixed evaluation set and compare new failures against historical regressions. Only when offline evaluation, shadow comparison, and the limited-scope phased rollout all meet the established thresholds is it appropriate to widen access.