AI SQL Generator
Turn a plain-English question into a SQL query.
This tool sends the text you enter to an AI provider to generate a response. Don't paste secrets or personal data. No files are uploaded.
Turn a natural language query about your data into SQL: ask in ordinary English and the AI SQL Generator writes the statement that would answer it, with a one-line explanation and a note of any assumptions it had to make.
How to use it
- 1Type the question in the first box — 'top five customers by total order value in 2024'.
- 2Fill in Table / schema details if you have them; the field is optional, but listing your tables and columns is what stops the model inventing names.
- 3Press Generate SQL, then read the query through before pointing it at anything live.
Example
- Input
- Top 5 customers by total order value in 2024 · customers(id, name), orders(id, customer_id, total, created_at)
- Output
- A SELECT joining orders to customers, summing total, grouping by customer, filtering created_at to 2024 and ordering descending with a limit of 5, followed by a single line explaining it.
Standard SQL is the default, so a LIMIT comes back rather than TOP or FETCH FIRST unless you name your dialect in the question. Nothing executes the query and no database is connected, so the model cannot tell whether your columns are indexed or even whether they exist — with the schema box left empty it will simply guess plausible names and say so.
What happens to your data
The two boxes are not sent on equal terms: the question always goes, while the schema is appended under a 'Schema:' heading only when you have typed something into it, so leaving it blank genuinely keeps your table layout on your side. Whatever is sent travels through our /api/ai route to Anthropic's Claude API, which is what composes the query. A schema is a description of your system, so limit it to table and column names — never connection strings, credentials, or real rows copied out of a table.
Last updated August 2026
You know exactly what you want out of the database and cannot remember the shape of the query that gets it. Or a colleague wants last quarter's figure broken down by month, and the query that nearly does it was written by someone who has left. That gap — between a clear question and the syntax that answers it — is what a generator is for.
Decide one thing before you type: whether you are handing over your schema. Leave it empty and you get the shape of the answer with invented table and column names, which you rename yourself. Fill it in and you get something much closer to runnable, at the cost of describing your tables to a third party. Both are reasonable; choosing by accident is not.
The other thing to settle is which database you are writing for. SQL is a family rather than a language, and it diverges exactly where reporting queries live: date truncation, string concatenation, identifier quoting, row limiting. Name the engine in your question and most of that goes away.
Then read what comes back for what it does, not for whether it looks like SQL. Generated queries fail quietly — a join that multiplies rows before a SUM, a date range that drops its final day, a LEFT JOIN turned into an inner join by a stray WHERE condition. Each runs perfectly and returns the wrong number.
How it works
Toolvore wraps your question in a single instruction line and posts it to a route on this site, which forwards it to Anthropic's Claude with a fixed brief: use standard SQL unless a dialect is named, return the query in a code block, add a one-line explanation, and where the schema is ambiguous make reasonable assumptions and state them. The answer streams in as it is written, with a Stop button while it runs and Copy once it finishes. The weakness is structural: nothing here parses your schema or connects to anything, so a column you mistyped is copied faithfully into the query and a table that no longer exists is used with confidence. The reply is capped, and if it reaches that ceiling the text stops mid-flow and a bracketed note says so. Each run starts clean with no memory of the last, so a refinement has to carry its own context.
Common use cases
- Turning a stakeholder's question into a starting query
- Recalling a window function you write twice a year
- Drafting a join across unfamiliar tables
- A first GROUP BY with a HAVING clause
- Writing in a dialect you rarely use
- Sketching a query before checking it against the schema
Frequently asked questions
Why does my total come out too high after I add a join?+
Almost always row multiplication, or fan-out. A join pairs every row on the left with every matching row on the right, so a customer with three addresses turns one order into three rows and SUM(total) triples. Nothing looks wrong; the arithmetic is being done on a bigger table than you pictured. Check by dropping the aggregate and counting the rows the join produces, against the row count of the table you meant to sum. The fixes: aggregate each side in a subquery before joining, or move the extra table into a scalar subquery where it cannot multiply anything.
Why does my LEFT JOIN behave like an INNER JOIN?+
A condition on the right-hand table sitting in the WHERE clause. A LEFT JOIN keeps unmatched left rows and fills the right-hand columns with NULL. The WHERE clause runs afterwards, and NULL fails almost every comparison, so those rows are discarded and you are back to an inner join. Move the condition into the ON clause, where it decides which rows match rather than which rows survive. The deliberate exception is IS NULL: keeping orders.id IS NULL in the WHERE is the standard anti-join, the way you find left rows with no match at all.
What does GROUP BY do, and why does it keep rejecting my columns?+
GROUP BY collapses many rows into one per distinct combination of the grouping columns. A column you did not group then has several possible values and one slot, so the database refuses rather than guess — hence the error about a column having to appear in the GROUP BY clause or be used in an aggregate. Add it to the GROUP BY, or wrap it in MIN or MAX. WHERE and HAVING split on the same line: WHERE filters rows before grouping, HAVING filters the groups afterwards, which is why a count can only be tested in HAVING.
How do I filter a date range without losing the last day?+
If the column holds a timestamp rather than a plain date, BETWEEN '2024-01-01' AND '2024-01-31' quietly excludes nearly all of the 31st: the end value is read as midnight, so everything later that day falls outside. Write it instead as greater than or equal to the start and strictly less than the day after the end. That holds whether the column is a date, a timestamp or a timestamp with a time zone, and needs no special case for month lengths. A related trap: wrapping the column in a cast or date function usually stops an index being used.
Where do my question and my schema actually go?+
The question is posted to a route on this site and forwarded to Anthropic's Claude API, which writes the query; the schema goes only when you have filled that box in. Nothing is executed and no database is connected, so there is nowhere to enter credentials and no reason to. Each run is independent: the previous question is not resent, and the result area is cleared before the new answer arrives. One caution particular to this tool: instructions inside your input are acted on, because here that is the point, so paste schema you wrote rather than text of unknown origin.
How portable is standard SQL between databases?+
The core travels well: SELECT, JOIN, GROUP BY, HAVING and ordinary comparisons move between engines untouched. The edges do not. Dates diverge worst — DATE_TRUNC in PostgreSQL, DATE_FORMAT in MySQL, strftime in SQLite, DATEPART in SQL Server — and string concatenation is a double pipe in some engines and CONCAT in others. Identifier quoting splits three ways: double quotes, backticks, square brackets. Row limiting and upserts vary by version as well as by engine. Name the database and the version — a query written for the wrong engine usually fails loudly, the better outcome.
Is it safe to run a query somebody else wrote against production?+
Read it for what it does before what it returns. Confirm it is a SELECT and nothing more; if you did ask for an UPDATE or DELETE, confirm the WHERE clause is the one you meant and that no join widens its reach. Then run it where it cannot hurt — a read replica, a staging copy, or inside a transaction you roll back. Attaching a LIMIT and running EXPLAIN first tells you both the shape of the result and whether you are about to scan the whole table. A generated query has never seen your data.
Why is my query slow when it looks simple?+
Run EXPLAIN and read the plan the database chose rather than guessing. A sequential scan over a large table usually means no usable index on the columns you filter or join by. The recurring causes: a function or cast applied to the column in the WHERE clause, which hides it from the index; a LIKE pattern with a leading wildcard; ORDER BY with a large OFFSET, which makes the engine produce and discard everything before the offset; and a correlated subquery evaluated per row where a join would do the job once. Indexes speed reads and slow writes.