SQL query generator: from a plain-English question to a tested query
Writing the right JOIN or window function from memory is slow, and a wrong GROUP BY gives numbers that look fine but aren't. Paste your table structure and ask your question in plain English. Your todo.is agent writes a commented query for your database, runs it against sample data in its workspace and shows you the result.
The prompt
- Write a SQL query for [DATABASE TYPE] that answers: [YOUR QUESTION]. My tables: [TABLE STRUCTURE]. Add comments explaining each part, use clear aliases, and avoid anything that would be slow on [TABLE SIZE]. Create a small sample dataset that matches my tables, run the query on it in your workspace and show me the output, so I can see it works. If anything in my question is ambiguous (like how to count refunds), tell me what you assumed.
What to change
- [DATABASE TYPE]: E.g. "PostgreSQL 15", "MySQL 8", "SQL Server", "SQLite", "BigQuery", "Snowflake".
- [YOUR QUESTION]: Plain English, e.g. "top 10 customers by revenue in the last 90 days, with their order count".
- [TABLE STRUCTURE]: Paste CREATE TABLE statements or list tables and columns, e.g. "orders(id, customer_id, total, status, created_at)". Or attach a schema file.
- [TABLE SIZE]: Rough row counts, e.g. "orders has 20 million rows". Or "small, under 100k rows".
Example result
- Top 10 customers by revenue, last 90 days (PostgreSQL)
- -- Paid orders from the last 90 days, refunds subtracted
- WITH recent AS (
- SELECT o.customer_id,
- o.id AS order_id,
- o.total - COALESCE(r.amount, 0) AS net_total
- FROM orders o
- LEFT JOIN refunds r ON r.order_id = o.id -- keep orders with no refund
- WHERE o.status = 'paid'
- AND o.created_at >= now() - interval '90 days'
- )
- SELECT c.id,
- c.name,
- COUNT(*) AS orders,
- SUM(rc.net_total) AS revenue
- FROM recent rc
- JOIN customers c ON c.id = rc.customer_id
- GROUP BY c.id, c.name
- ORDER BY revenue DESC
- LIMIT 10;
- What each part does
- • WITH recent AS (...) gathers the orders you care about first, so the main query stays readable
- • LEFT JOIN refunds keeps orders that were never refunded; COALESCE turns their missing refund into 0
- • GROUP BY c.id, c.name gives one row per customer; grouping by id avoids merging two customers with the same name
- • ORDER BY revenue DESC LIMIT 10 keeps the top 10
- Sample run (500 fake orders, 60 customers)
- • 1. Northwind Cycles: 14 orders, 8,920.00
- • 2. Juniper Studio: 9 orders, 7,410.50
- • 3. Alder & Finch: 11 orders, 6,985.00
- Assumptions
- • "Revenue" means paid orders minus refunds; pending and cancelled orders are excluded
- • One refund row per order at most. If you allow several, the refunds should be summed per order first
- Performance on 20M rows
- • An index on orders (status, created_at) lets the WHERE clause skip old rows
- • Run EXPLAIN ANALYZE before using it in a dashboard
How to do it with todo.is
- Copy the prompt, then fill in your database type, your question and your tables.
- Paste your CREATE TABLE statements, or attach a schema export, on the Today screen in todo.is.
- Your agent writes the query, runs it on realistic sample data and shows the result table.
- Copy the query (or download the .sql file) and run it in your own database tool.
- Send back any error message or odd number and it fixes the query.
Tips for a better result
- Always name your database. Date functions, LIMIT versus TOP and string handling differ between PostgreSQL, MySQL, SQL Server and BigQuery.
- Share the structure, not the data. Column names and types are enough to write a correct query.
- Define tricky words like "active customer" or "revenue" in the question; most wrong numbers come from unclear definitions.
- Test new queries on a read-only user or a copy of the database before running UPDATE or DELETE statements.
- Make it recurring if you need the same report weekly: your agent can rebuild the sample checks and email you the query notes.
SQL query generator: FAQ
- Can it connect to my database and run the query? No. It doesn't log in to your database. It runs the query on sample data in its own workspace, and you run the final query in your own tool.
- What is the difference between WHERE and HAVING? WHERE filters rows before grouping, HAVING filters groups after aggregation. For example, HAVING COUNT(*) > 5 keeps only customers with more than 5 orders.
- Can it explain or speed up a slow query I already have? Yes. Paste the query and, if you can, the EXPLAIN output. It points out missing indexes, unneeded subqueries or functions on indexed columns, and rewrites it.
- Is it safe to paste my schema? Your schema stays in your own agent workspace and only your agent uses it. Leave out real data and credentials; they aren't needed.
JavaScript is required to use the todo.is app.