OmniSelect FileSQL

Guides
← Back to App
HomeGuides › Plain English to SQL

Plain English to SQL, With No AI

Type total salary by department and the SQL appears as you finish the sentence. No language model is involved, no API key, no per-query cost, and nothing about your file — not even a column name — leaves the browser tab.

Why That Last Part Matters

Every other text-to-SQL box you have used is a network call. To turn your question into SQL, the service needs to know what your columns are called, so your schema goes in the request. Many send sample rows as well, to work out what the values look like. That is a reasonable engineering decision and a serious problem if the file is a client extract, a payroll export or a patient list.

This one works differently. It reads your file where the file already is, builds a picture of the tables and columns in memory, and matches your sentence against that picture using an ordinary parser. There is no request to make, so there is nothing to intercept, log or leak.

💡 You can check this rather than believe it. Open the browser's network panel, keep it recording, and type a few questions. The request count does not move. The full verification guide walks through it.

Using It

  1. Add a file. Drag it onto the File Select panel. It becomes a SQL table named by a single letter, shown in the Alias column — employees.csv becomes E.
  2. Type your question in the Ask in Plain English box, on the left of the SQL Editor.
  3. Read the SQL that appears on the right. It is ordinary SQL, and it is editable — correct it, extend it, or ignore the English box entirely from that point.
  4. Run it with the Run Query button or Ctrl+Enter.

The SQL regenerates about a third of a second after you stop typing. There is no Generate button to press.

Add a file and ask it something.

Open the app →

What It Understands

These are run against a 48-row employees.csv with the columns employee_id, first_name, last_name, department, city, salary and hire_date. The SQL shown is exactly what appears in the editor.

What you typeWhat you get
total salary by departmentSELECT department, SUM(salary) AS total_salary FROM E GROUP BY department
average salary by citySELECT city, AVG(salary) AS avg_salary FROM E GROUP BY city
top 5 employees by salarySELECT * FROM E ORDER BY salary DESC LIMIT 5
employees in engineeringSELECT * FROM E WHERE department = 'Engineering'
show me 3 employeesSELECT * FROM E LIMIT 3
which department has the highest total salarySELECT department, SUM(salary) AS total_salary FROM E GROUP BY department ORDER BY total_salary DESC LIMIT 1
employees earning more than the average salarySELECT * FROM E WHERE salary > (SELECT AVG(salary) FROM E)
rank employees by salary within each departmentSELECT *, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank FROM E
top 2 employees per department by salarySELECT * FROM E QUALIFY ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) <= 2 ORDER BY salary DESC, department ASC

The SQL says LIMIT only when you ask for a number of rows, as in top 5 or show me 3. How many rows come back otherwise is set by the Row limit box beside Export: 1,000 unless you change it. An export always holds every row of the result.

Three Things Worth Knowing

It reads the values, not just the headers

employees in engineering becomes department = 'Engineering' — with the capital E. Nobody told it that Engineering lives in the department column, or how it is spelled in your file. It read the column, saw that it holds a small set of repeated values, and matched your word against them. That is also why the capitalisation comes out right even though you typed it in lower case.

Dates become real ranges

employees hired last year produces:

SELECT * FROM E
WHERE hire_date >= '2025-01-01' AND hire_date < '2026-01-01'

It found the date column by type rather than by name, worked out the boundaries from today's date, and wrote them out literally so the query still means the same thing when you save it and run it next month. The range runs up to the first day of this year rather than to the last day of last year, so a timestamp late on 31 December is still counted.

Spelling does not have to be right

Type total salry by departmnt and you get the same query as the correctly spelled version. Column and value names are matched by edit distance, and any correction it made is reported rather than applied silently.

Where It Stops

It is a parser with a grammar, not a model that will have a go at anything. That is a deliberate trade, and the honest shape of it is this: within what it covers it is exact and repeatable, and outside that it says so rather than inventing a query.

CoveredNot covered
Select, where (conditions joined by and or or), group by, having, order by, limitPercentages and ratios — it says so rather than guessing
Joins across up to 26 files, found from the data itselfAnything that changes data — no insert, update or delete exists here at all
Counts, sums, averages, medians, standard deviations, minimums, maximums, and conditions on them ("regions with total sales over 10,000")Multi-sentence questions, or questions with a "because" in them
Rankings, running totals, moving averages, top N within each group, and a place in a ranking ("second highest salary", "3rd largest order", "second highest salary per department")Multi-step questions that need a query inside a query, beyond "above the average"
Comparisons with the average: "above the average salary"Business logic it cannot see: "active customers", if nothing in the file says what active means
Relative dates (today, last week, last 30 days, last year), named months ("march 2024"), month ranges ("between January and March 2023"), and totals by day, week, month, quarter or year ("revenue by month")

When it cannot place part of your sentence it tells you which words it did not use, rather than quietly dropping them and returning a confident, wrong answer.

Joins, Without Writing the Join

Load two files that share a key and ask a question that spans both. With customers.xlsx and orders.xlsx loaded as C and O, total amount by city gives:

SELECT C.city, SUM(O.amount) AS total_amount
FROM C
JOIN O ON C.customer_id = O.customer_id
GROUP BY C.city

The join condition was not typed and not guessed from the column name alone. A name match is only half the evidence; the other half is checking that the values in one column actually occur in the other. Both have to agree before a relationship is used, which is what stops a quantity column being joined to a customer_id because the numbers happen to overlap.

Reasonable Questions

Is there really no model behind this?

No. There is a tokenizer, a phrase index built from your file's own column and value names, and a compiler that turns matched phrases into an abstract syntax tree, which is then printed as SQL. It is about 280 kilobytes of compiled WebAssembly that ships with the page. The network panel is the proof, and it costs you nothing per query because there is nothing to bill.

What happens to my column names?

They stay in the tab. They are used to build an in-memory index and are discarded when you close it. No copy is stored, sent or logged.

Can I edit the SQL it writes?

Yes — the editor is editable by default and always was. The English box is a starting point, not a wrapper. Many people use it for the first draft of a query and then hand-edit from there, which is exactly the intended use.

What if it gets the query wrong?

You will see it, because the SQL is on screen before anything runs. There is a confidence note above the editor, and it says not sure · check the SQL when the match was weak. Nothing executes until you press Run.

Does it work offline?

Yes. Because there is no service to call, it behaves identically with the network disconnected. Here is that demonstrated.

Which languages does it understand?

English only, at present.

Related Guides