Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path
SQL Formatter
A lightweight SQL formatter. Paste a cramped, one-line query and get it back with each major clause on its own line, keywords cased consistently, and conditions indented — so you can actually read and review it. Runs in your browser; it formats for readability rather than parsing the full SQL grammar.
SELECT u.id,
u.name,
COUNT(o.id) AS orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
WHERE u.active = 1
AND u.country IN ('US','CA')
GROUP BY u.id,
u.name
HAVING COUNT(o.id) > 3
ORDER BY orders DESC
LIMIT 10A query’s logic does not depend on its layout, but your ability to review it does. Paste a cramped one-line query and the tool rebuilds it with one clause per line, standard keywords in capitals and conditions indented beneath their clause. It is a fast, rule-based pass rather than a parser, and knowing its rules tells you when to trust it.
What it computes
The formatter applies seven text rules in a fixed order:
- Protect literals. Single-quoted strings, including
''escapes, double-quoted identifiers and backtick identifiers are set aside so no later rule can touch them. - Collapse whitespace. Every run of spaces, tabs and newlines becomes one space.
- Uppercase keywords. A fixed list of 50 words, from
SELECTandJOINtoCOUNT,CASEandDESC, is capitalized wherever it appears as a whole word. - Split top-level commas. A comma outside all parentheses ends the line, so each selected column or
GROUP BYkey gets its own row. Commas insideCOUNT(...)orIN (...)are left alone. - Break before clauses. 26 clause markers start a new line at the left margin, matched longest first so
LEFT OUTER JOINandDELETE FROMstay whole. They are the join forms,UNION,INTERSECT,EXCEPT,SELECT,FROM,WHERE,GROUP BY,HAVING,ORDER BY,LIMIT,OFFSET,INSERT INTO,VALUES,UPDATEandSET. - Indent conditions.
AND,ORandONeach start a line indented two spaces. - Tidy and restore. Trailing spaces are trimmed, and the protected literals are put back exactly as typed.
A worked example
The default input is one 217-character line:
select u.id, u.name, count(o.id) as orders from users u left join orders o on o.user_id = u.id where u.active = 1 and u.country in ('US','CA') group by u.id, u.name having count(o.id) > 3 order by orders desc limit 10
The formatter returns 13 lines:
SELECT u.id,
u.name,
COUNT(o.id) AS orders
FROM users u
LEFT JOIN orders o
ON o.user_id = u.id
WHERE u.active = 1
AND u.country IN ('US','CA')
GROUP BY u.id,
u.name
HAVING COUNT(o.id) > 3
ORDER BY orders DESC
LIMIT 10
The two top-level commas after SELECT put u.name and COUNT(o.id) AS orders on their own lines, while the comma inside ('US','CA') sits inside parentheses and stays put. left join matches the two-word marker LEFT JOIN before the bare JOIN, so the whole phrase opens the line, and on drops to an indented ON beneath it. The literals 'US' and 'CA' were protected, so their case is untouched. Comma continuation lines are indented three spaces rather than two, because the space after each comma survives the line break.
Assumptions and limits
- Comments are not recognized. Because all lines are joined into one, a
--comment can swallow code that followed it.select a -- the idwith, b from ton the next line comes out asSELECT a -- the id ,and thenb, which a database reads as columnaaliased tob. Remove line comments first. - No nesting. A subquery’s
SELECT,FROMandWHEREstart at the left margin like the outer query’s, and a window function’sORDER BYbreaks out of itsOVER (...). - Every AND is a condition. The
ANDinBETWEEN 1 AND 5also moves to its own line. - A fixed keyword list.
WITH,OVERandPARTITIONkeep the case you typed, while an unquoted column namedcountorendis capitalized. - Generic quoting only. PostgreSQL dollar-quoted bodies and SQL Server square-bracket names are not protected.
How to use the result
- Read the left margin first.
SELECT,FROM, the joins,WHERE,GROUP BY: top to bottom, it tells you whether the query does what the ticket says before you read any detail. - Check every join has its ON. An indented
ONunder each join line is the quickest way to spot an accidental cross join. - Watch mixed AND and OR. At the same indentation they still evaluate
ANDfirst, so add parentheses if you meant otherwise. - Paste the formatted query into reviews. One clause per line makes later diffs show the clause that changed.
- Execute the original. For queries with comments or dialect-specific syntax, run what you wrote and use the formatted copy for reading.
How it works
- Each major clause on its own line, standard keywords uppercased.
- Top-level commas and AND / OR / ON conditions get their own indented lines.
- Leaves string literals and quoted identifiers untouched.
- Lightweight and dialect-agnostic: readability, not full parsing.
Frequently asked questions
What does the SQL formatter actually do?
It applies a fixed set of text rules. It protects quoted strings and identifiers, collapses all whitespace, uppercases 50 standard keywords, and starts a new line at every top-level comma. Each of 26 clause markers, such as SELECT, FROM, the JOIN variants, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, UNION, VALUES and SET, begins a new line at the left margin, and AND, OR and ON go on indented lines beneath their clause. The result is the same query laid out so its structure can be scanned.
Does formatting change what my query does?
For ordinary SQL, no. It changes only whitespace and the case of keywords, and SQL keywords are case-insensitive, while string literals and quoted identifiers are restored exactly as typed. The exception is comments. The formatter does not recognize them, and because it joins every line into one, code that followed a double-dash comment on the next line can end up inside that comment. Remove line comments before formatting, or run your original query and keep the formatted copy for reading.
Is this a full SQL parser?
No, and that is a deliberate trade-off. It is a lightweight, dialect-agnostic formatter built from pattern rules, which handles everyday SELECT, INSERT, UPDATE and DELETE statements well. It does not track nesting, so a subquery starts its clauses at the left margin, a window function splits at its ORDER BY, and the AND inside BETWEEN 1 AND 5 moves to its own line. For deeply nested or vendor-specific SQL, a dialect-aware formatter in your IDE or database client will do better.
Why uppercase SQL keywords?
It is a long-standing convention that separates the language, words like SELECT, WHERE and JOIN, from your own table and column names, so a reviewer can see the shape of a query at a glance. It is purely stylistic, because SQL keywords are case-insensitive in every major database. If your team prefers lowercase keywords, that works just as well; what matters is that everyone writes the same way, so diffs show real changes rather than casing noise.
Which words get uppercased?
A fixed list of 50 keywords, covering clauses, joins, set operators, comparisons such as IN, IS, LIKE and BETWEEN, the aggregates COUNT, SUM, AVG, MIN and MAX, CASE expressions, and ASC and DESC. Words outside the list, such as WITH, OVER, PARTITION or CREATE, keep the case you typed. Matching is by whole word, so an unquoted column named count or end is capitalized too, while anything inside quotes, such as a column written as "order", is never changed.