SQL Query Formatter
Beautify SQL with configurable indentation, keyword casing and dialect support for PostgreSQL, MySQL, SQL Server, SQLite and Oracle.
Paste a query — or a whole script of them — and the formatter rebuilds it with a consistent
style: major clauses at column zero, joins aligned with FROM, AND/OR
and subqueries indented, long column lists split one item per line. Pick the dialect you are targeting and
the formatter applies that engine's conventions — TOP vs LIMIT,
:: casts, GO batch separators, N' wide strings,
# comments — while minify mode squeezes the script back to a single line.
Your SQL
Tip: press Ctrl+Enter (or ⌘+Enter) inside the box to format.
How the formatter indents your queries
Every rule below is applied as you type, so the output is stable and diff-friendly:
- Major clauses start at column zero.
SELECT,FROM,WHERE,GROUP BY,HAVING,ORDER BY,LIMIT,UNIONand their friends each begin a new line at the outermost level. - Joins align with
FROM.LEFT JOIN,CROSS JOINand the rest sit at the same indent asFROM; theirON/USINGconditions step in one level. - Conditions step in.
AND/ORlines are indented one level under the clause they belong to, so a ten-conditionWHEREreads as a tree. - Subqueries and CTE bodies are indented. Anything inside a
(SELECT …)or aWITHbody gets one extra level, and the closing parenthesis returns to the outer level. CASEarms are indented.WHEN/THEN/ELSEsit one level in;ENDaligns withCASE.- Long lists split one item per line. When a line passes your wrap width, column lists, function arguments and
VALUESrows break after each comma. - Statements are separated by blank lines, and comments are preserved where you wrote them.
- Keyword casing touches keywords only. Identifiers, table names and string contents keep their original casing.
Dialect differences that matter
The same logical query is spelled differently on each engine. The formatter's dialect profile knows
these conventions, so it never mangles a TOP (10), splits a GO batch in
half, or treats a # comment as an operator:
| Feature | PostgreSQL | MySQL | SQL Server | SQLite | Oracle |
|---|---|---|---|---|---|
| Quoted identifier | "col" | `col` | [col] | "col" or `col` | "col" |
| Top-N rows | LIMIT n | LIMIT n | TOP (n) | LIMIT n | FETCH FIRST n ROWS ONLY / ROWNUM |
| Pagination offset | LIMIT n OFFSET m | LIMIT m, n | OFFSET (m) ROWS FETCH NEXT n ROWS ONLY | LIMIT n OFFSET m | OFFSET m ROWS FETCH NEXT n ROWS ONLY |
| Boolean literals | TRUE / FALSE | 1 / 0 | 1 / 0 | 1 / 0 | 1 / 0 |
| Line comments | -- | -- and # | -- | -- and # | -- |
| Parameter placeholders | $1, ?, :name | ? | @name | ?, :name, @name | :name |
| Type cast | x::int or CAST | CAST | CAST / CONVERT | CAST | CAST / TO_NUMBER |
| String concatenation | a || b | CONCAT(a, b) | a + b or CONCAT | a || b | a || b |
| Empty string vs NULL | distinct | distinct | distinct | distinct | '' is NULL |
What the formatter does — and does not
This is a formatter, not a linter: it reflows what you give it and never rewrites logic. It will not
add a missing GROUP BY column, convert LIMIT to TOP for you,
or tell you a join is missing an ON clause. The dialect profile only changes how the
formatter recognises engine-specific syntax (quoted identifiers, comments, casts, batch
separators, placeholders) so that none of it gets mangled. If you need to convert a query
between dialects, do that pass by hand — the formatted output is the cleanest place to start.
Nothing on this page leaves your browser: there is no server round-trip when you paste, format or minify, no analytics on your inputs, and no storage of any kind.