The gap between a query that parses and a query that is right is your schema. Here is how that gap gets closed.
Translating "how many customers churned last month" into SQL is trivial once you know that churn is `subscriptions.cancelled_at`, that a customer is a row in `accounts` rather than `users`, and that the two join through `account_id`. Knowing that is schema linking, and it is where systems fail. The SQL grammar is small and every current model has it; your schema is large, private, and nothing was trained on it.
It works for the sample database in the tutorial. At two thousand tables the schema does not fit in a context window, and even where it fits, burying eight relevant tables in two thousand irrelevant ones measurably degrades the answer. SQLore builds a retrieval index over the schema locally — names, types, keys, distinct values, statistics — and searches it per question, so the model sees the eight tables the question is about and not the rest.
A one-shot system hands you a query and you find out at the meeting that the join fanned out. An agentic system runs the query itself and reads what came back. Zero rows from a question that should return thousands is a signal. A sum that is exactly four times too large is a signal. SQLore acts on those signals before returning an answer, which is why the query you are shown is the one that survived rather than the first one drafted.
Letting a model run generated SQL against your database is only reasonable if the generated SQL provably cannot do damage. SQLore parses every statement to an AST and validates it down to a single read-only SELECT — no writes, no DDL, no multiple statements, no stacked queries — then runs it on a read-only connection with a statement timeout. The guarantee is structural, so the agentic loop costs you nothing.
On first connection it reads the system catalog: tables, columns, types, primary and foreign keys, and statistics. The result is cached locally so this happens once, not per question.
Your question is matched against that index on your own machine. A two-thousand-table database yields the eight tables the question is about.
The model writes SQL against the retrieved slice — real table names, real keys, real column values — on a local model by default or a live one if you asked for it.
The statement is parsed to an AST, validated to a single read-only SELECT, and executed on a read-only connection under a statement timeout.
If the result contradicts the question, it revises and runs again. You are shown the query that worked, the rows it returned and how long it took.
More answers on the main FAQ, or ask us directly.
For people who already write SQL
The category, explained
For analysis
Every page in this section covers a different question about the same product. See all solutions.
Start free, upgrade when you are asking enough questions for it to matter.