⚙️ Developer Tools Free Forever

SQL Query Explainer: Plain-English Breakdown & Tips

Paste a SQL query and get a clause-by-clause plain-English explanation, plus rule-based suggestions for common mistakes like missing WHERE clauses or SELECT *.

SQL Query
About This Tool

Plain-English SQL explanations from pattern matching, not a database engine

This is worth stating clearly: this tool does not connect to a database and does not produce a real execution plan the way EXPLAIN does in Postgres or MySQL. It reads the text of your query, finds clause keywords with a keyword-detecting regex, and builds a sentence for each clause describing what that clause does structurally. It also runs a short list of rule-based checks for common query smells. Everything happens in the browser; no query text is transmitted anywhere.

Why string literals get masked before scanning

A naive keyword search would break the moment someone's WHERE clause filters on a string containing the word from or select. Before any clause detection runs, the tool builds a masked copy of the query where every character inside a quoted string is replaced with the letter x, keeping spaces intact so lengths and word boundaries still line up. Clause keywords are searched for in this masked copy, but the original text is used when displaying the clause body back to you.

Step 1 Mask strings Every character between a pair of quote marks becomes an x, so a literal keyword sitting inside a string can never falsely trigger clause detection.
Step 2 Find clause boundaries Everything inside parentheses is masked too, so only the top level of the statement is scanned. A combined regex then finds SELECT, FROM, WHERE, every JOIN type, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET, FETCH, UNION, INTERSECT and EXCEPT, recording where each one starts. Subqueries found inside parentheses are explained on their own, one level at a time.
Step 3 Slice into clauses Each clause's body is everything between its keyword and the start of the next detected keyword, taken from the real, unmasked query text.
Step 4 Describe each clause A dedicated function per clause type builds a sentence: SELECT lists and aliases columns, JOIN identifies the ON or USING condition, ORDER BY reports ascending or descending per column, and so on.
// masking pass, run before any keyword detection function maskStrings(sql) { var out = '', i = 0; while (i < sql.length) { var ch = sql[i]; if (ch === "'" || ch === '"' || ch === '`') { var quote = ch; out += ch; i++; while (i < sql.length && sql[i] !== quote) { out += (sql[i] === ' ' ? ' ' : 'x'); i++; } } else { out += ch; i++; } } return out; }

The rule-based warnings

Alongside the clause breakdown, the tool applies a fixed set of checks and appends a warning whenever one triggers. These are heuristics, not guarantees; a query can trip a warning and still be perfectly correct for its context.

Condition detectedWarning raised
SELECT *Suggests naming specific columns to reduce data transfer and avoid breakage if columns are added later.
JOIN with no ON or USINGFlags a likely cross join, every row paired with every row, which is rarely intentional.
No LIMIT, TOP or FETCHWarns that an exploratory SELECT could return far more rows than expected. Skipped for grouped queries and single row aggregates.
Limit without ORDER BYNotes that the rows you get back are not guaranteed to be the same each run.
= NULL in a conditionExplains that this is never true and that IS NULL is needed.
LIKE starting with %Warns that a normal index cannot be used, so every row is scanned.
Function on a columnWarns that something like YEAR(created_at) = 2024 usually prevents index use.
NOT IN with a subqueryWarns that one NULL in the subquery makes the whole condition return nothing, and suggests NOT EXISTS.
AND with OR, no parenthesesReminds you that AND binds tighter than OR.
Comma join, no WHEREFlags an accidental cross join.
ORDER BY RAND()Warns that the whole table is sorted on every run.
Large OFFSETSuggests keyset paging, because skipped rows are still read.
UPDATE with no WHEREFlags that every row in the table would be modified.
DELETE with no WHEREFlags that every row in the table would be removed.
INSERT with no column listWarns that values are assumed to be in the table's exact column order, which breaks silently if the schema changes.
Wrong value countFlags a row that does not match the listed columns, which the database would reject.
DROP or TRUNCATEReminds you that the data is gone for good without a backup.
What it reads, and what it does not. SELECT, INSERT, UPDATE and DELETE get a full clause by clause explanation, including queries that start with WITH and any subqueries inside them. CREATE TABLE, CREATE INDEX, CREATE VIEW, ALTER TABLE, DROP and TRUNCATE get a short description. Several statements separated by semicolons are explained one after another. Stored procedures and vendor specific control flow are not parsed, and you get a clear message instead of a wrong explanation.

Column and JOIN parsing detail

Top-level comma splitting

Column lists are split on commas, but only at parenthesis depth zero, so a function call like COALESCE(a, b) inside a SELECT list is not incorrectly broken into two separate columns.

Alias detection

Both explicit AS aliases in SELECT lists and implicit table aliases in FROM and JOIN clauses are matched with dedicated regex patterns and rendered as "renamed to" or "aliased as" in the explanation.

SELECT, INSERT, UPDATE, DELETE, WITH Every JOIN type recognized String-literal masking before parsing Rule-based query smell warnings

Database documentation

Queries worth explaining

Reviewing a teammate's pull request that includes a raw SQL migration or query, understanding a legacy query inherited from a previous engineer, double checking an UPDATE or DELETE statement's WHERE clause before running it against production, and getting a quick sanity check on a generated query from an ORM or query builder before trusting it.

Common Questions

FAQ: SQL Query Explainer

No, this tool never connects to a database or executes anything, it only reads and pattern-matches the text of your query to explain its structure. It's completely safe to paste queries containing real table or column names, since nothing is executed or transmitted anywhere.

The explainer reads SELECT statements (every JOIN type, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET, TOP, FETCH, UNION, INTERSECT and EXCEPT), queries that start with WITH, and INSERT, UPDATE and DELETE statements. CREATE, ALTER, DROP and TRUNCATE get a short description. Highly vendor-specific syntax may not parse perfectly.

SELECT * pulls back every column in a table, including ones you don't need and ones that might be added later, which increases data transfer, can silently break application code that expects a fixed column order, and makes a query's actual intent harder to read. Explicitly naming the columns you need is considered better practice in most production codebases.

An UPDATE or DELETE without a WHERE clause applies to every single row in the table, this is one of the most common and most damaging SQL mistakes, often caused by accidentally running a statement before finishing the WHERE clause. This tool flags it clearly so you catch it before running the query against a real database.

A JOIN normally needs a matching condition (using ON or USING) to determine how rows from the two tables relate to each other. Without one, most databases perform a cross join, pairing every row in one table with every row in the other, which can silently produce a massive, incorrect result set and put heavy load on the database.

Yes. Each subquery is explained on its own, with a label that says where it sits, for example inside WHERE or an IN list. Queries that start with WITH get a short line per CTE, then the main query, then a breakdown of what each CTE does. Very deep nesting is cut off after four levels to keep the result readable.

No, this tool explains what a query does in plain language and flags a handful of common structural mistakes, it does not analyze performance, indexes, or execution plans. For performance analysis, use your database's own EXPLAIN or EXPLAIN ANALYZE command, which reflects your actual data and schema.