ToolActToolAct

SQL Formatter

SQL Input
Formatted Output
Lines: 1Characters: 0Bytes: 0
Lines: 1Characters: 0

What is SQL Formatting?

The SQL Formatter structures SQL queries with consistent indentation, line breaks, and clearly visible clauses. SELECT, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, CTEs, and subqueries become easier to read, which helps reviews, debugging, teaching, and analysis of long reports. Formatting can also make accidental cross joins, crowded conditions, or misplaced parentheses easier to spot. It does not change database logic, optimize execution plans, guarantee dialect portability, or make unsafe dynamic SQL safe. For production changes, parameterization, permissions, indexes, transactions, locking behavior, and the actual query plan still need review in the target database.

How to Use

How to use

  1. Paste or enter SQL statements in the left input box
  2. Select indent size (2 spaces, 4 spaces, or Tab) and keyword case
  3. Click "Format" to beautify SQL or "Minify" to remove whitespace
  4. Results appear on the right with syntax highlighting
  5. Click "Copy" or "Download" to save results

SQL Review Notes

  • Formatting improves readability but does not validate permissions, indexes, execution plans, or business correctness.
  • Before running changed SQL, review generated clauses, string literals, comments, and database-specific syntax manually.

Use Cases

Turn a dense SQL query into reviewable clausesPaste a long SELECT, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, or INSERT statement and the formatter breaks major clauses onto separate lines with indentation. The result is easier to review, debug, and explain when an ORM or reporting tool generated one dense line.
Match keyword casing to team or database styleChoose uppercase or lowercase keywords while keeping string literals, comments, and dollar-quoted blocks protected. This standardizes snippets for migration files, dashboards, runbooks, and internal documentation without manually hunting for every SELECT, JOIN, CASE, or aggregate function. Because parsing happens locally in the browser, queries referencing internal table names, unreleased feature flags, or staging schemas can be reformatted without the SQL being routed through any third-party beautifier.
Compress SQL for transport after reviewing itUse minify mode to remove block comments, line comments, repeated whitespace, and spaces around commas or parentheses. That is handy for URL parameters, fixtures, or compact config values, but it should be applied after you have already checked that the readable version means what you expect.
Format CTEs and subqueries with nested indentationCommon Table Expressions with WITH clauses and correlated subqueries gain an extra indent level so the outer SELECT, inner SELECT, and UNION blocks remain visually separated. This makes recursive CTE chains and EXISTS subqueries easier to follow during code review. Dialect detection matters here: PostgreSQL supports `DISTINCT ON (col)`, MySQL uses backtick identifiers and `IFNULL`, SQL Server uses bracket-quoted `[table]` and `TOP n` instead of `LIMIT`, and Oracle keeps `DUAL` and `ROWNUM`; the formatter aligns the major keywords (SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY) consistently, but the dialect-specific token list is the consumer's responsibility to verify.
Spot accidental Cartesian joins before they shipFormatting a multi-table SELECT with comma-separated FROM clauses makes it obvious when JOIN ... ON conditions are missing. The expanded layout exposes the bare table list where an extra row-multiplication row suddenly appears in production. Watch for parameters written as question-mark placeholders (used by MySQL prepared statements and many ORMs) versus dollar-1, dollar-2 numbering (PostgreSQL bind parameters) and colon-name named binds (Oracle and SQL*Plus); the formatter protects these tokens from being treated as identifiers, but the keyword case still has to match the team's chosen style (UPPER for migrations, lower for code review readability).

Technical Principle

SQL formatting is a three-stage pipeline: a tokenizer scans the raw text into a stream of tokens (keywords, identifiers, literals, operators, comments, whitespace), a parser groups those tokens by clause structure, and a printer walks the result emitting newlines, indentation, and casing per a style policy. The tokenizer must be dialect-aware because string and identifier delimiters differ: ANSI SQL uses double quotes for identifiers and single quotes for strings, MySQL uses backticks for identifiers, SQL Server uses square brackets, and PostgreSQL adds dollar-quoted blocks ($$...$$ or $tag$...$tag$) that escape every inner character including quotes.

The printing pass applies one rule per clause: SELECT / FROM / WHERE / GROUP BY / HAVING / ORDER BY / LIMIT each start a new line at column zero, projected columns and ON conditions indent one level (2 spaces, 4 spaces, or a tab), JOIN keywords (INNER / LEFT / RIGHT / FULL / CROSS) align under FROM, CASE / WHEN / THEN / ELSE / END are stacked vertically, and parenthesized subqueries and CTEs nested inside WITH receive an additional indent level so the outer SELECT remains visually anchored. String literals, line comments (-- ...), block comments (/* ... */), and dollar-quoted blocks are tokenized once and copied through unchanged so internal spacing is never touched.

Keyword casing is applied at print time, not via blind regex over the source — only tokens classified as RESERVED_KEYWORD are converted to UPPER or lower, so an identifier called 'order' or 'user' inside backticks stays in its original case. Dialect support matters because the reserved-word list differs by engine: PostgreSQL recognizes DISTINCT ON, RETURNING, ILIKE; MySQL adds IFNULL, LIMIT n,m, ENGINE=; SQL Server uses TOP n, OUTPUT, square-bracket identifiers; Oracle adds DUAL, ROWNUM, MINUS in place of EXCEPT; BigQuery and Snowflake extend the standard with QUALIFY, EXCEPT (columns), and array/struct literals. Performance is linear in source length (O(n) tokens, O(n) output bytes), so even multi-megabyte migration scripts format in milliseconds.
  • Tokenizer: scans source into RESERVED_KEYWORD, IDENTIFIER, STRING_LITERAL, NUMBER, OPERATOR, LINE_COMMENT (-- ...), BLOCK_COMMENT (/* ... */), and WHITESPACE classes; comments and strings are preserved verbatim
  • Dialect awareness: single-quoted strings (ANSI), backtick identifiers (MySQL), square-bracket identifiers (SQL Server), double-quoted identifiers (PostgreSQL/standard), dollar-quoted blocks $$...$$ (PostgreSQL)
  • Clause layout: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT each anchor at column 0; projected columns and ON conditions indent one level; JOIN keywords align under FROM
  • CTE and subquery indentation: WITH clauses indent the inner SELECT one extra level; correlated subqueries inside EXISTS / IN / scalar contexts receive their own indent so the outer query stays anchored
  • Casing policy: applied at print time per token class — only RESERVED_KEYWORD tokens are upper/lowercased, so identifiers like `order` or [user] retain their original case
  • Bind parameters: question-mark placeholders (MySQL prepared statements), dollar-1/dollar-2 numbered binds (PostgreSQL), and colon-name binds (Oracle/SQL*Plus) are tokenized as PARAMETER and never reformatted as identifiers
  • Complexity: O(n) lexing and O(n) printing where n = source length — multi-megabyte migration scripts format in milliseconds; comparable to the sql-formatter npm library, pgFormatter, and the Prettier SQL plugin

Examples

Format a dense SELECT with JOIN and WHERE

Input:  select u.id,u.name,o.total from users u left join orders o on o.user_id=u.id where u.status='active' and o.created_at>='2026-01-01' order by o.total desc limit 10;

Output:
SELECT u.id, u.name, o.total
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.status = 'active'
  AND o.created_at >= '2026-01-01'
ORDER BY o.total DESC
LIMIT 10;

Minify formatted SQL for a config string

Input (formatted, 6 lines):
SELECT id, name
FROM   products
WHERE  price < 100
  AND  stock > 0
ORDER  BY name;

Minified output (1 line, 78 chars):
SELECT id,name FROM products WHERE price<100 AND stock>0 ORDER BY name;

WITH (CTE) + nested subquery formatting

WITH recent_orders AS (
  SELECT user_id, SUM(total) AS spend
  FROM   orders
  WHERE  created_at >= NOW() - INTERVAL '30 days'
  GROUP  BY user_id
)
SELECT u.name, r.spend
FROM   users u
JOIN   recent_orders r ON r.user_id = u.id
WHERE  r.spend > (SELECT AVG(spend) FROM recent_orders);

Lowercase keywords (team style)

Settings: Indent = 2 spaces, Keywords = lowercase

Input:  SELECT * FROM Users WHERE Status=1;

Output:
select *
from users
where status = 1;

Use: matches Ruby on Rails / Django ORM-style migration files

FAQ

Which SQL dialects are supported?

Standard ANSI SQL plus common dialect-specific keywords: MySQL, PostgreSQL, MSSQL/T-SQL, SQLite, Oracle, BigQuery, Snowflake. Pick your target dialect from the dropdown so the formatter knows about dialect-specific keywords (LIMIT vs TOP, RETURNING, MERGE, etc.).

What style options are available?

Uppercase or lowercase keywords, indent size, leading vs trailing commas in column lists, max line length for wrapping, and whether to break before or after keywords. The page typically shows the options in a side panel.

Does it validate the SQL?

Most formatters parse loosely and pass questionable SQL through unchanged. Real validation needs a database connection (or at least a real SQL parser like sqlparse, sqlglot). Use this for layout; use your IDE or actual database for syntax checking.

Will it format stored procedures and triggers?

Most builds handle CREATE PROCEDURE / CREATE FUNCTION / triggers up to dialect-supported limits. Very long bodies with control flow (IF/ELSE/WHILE) format correctly; vendor extensions (T-SQL specific keywords) need the right dialect set.

Is my query uploaded?

No. Formatting runs in your browser using a JavaScript SQL parser. Pasted SQL is not transmitted. That said, never paste real production credentials or PII in any web tool.

Why are my CTEs and joins indented strangely?

Different formatters disagree on CTE alignment. Some indent each CTE definition; others keep them flush-left. Joins similarly have multiple valid styles ('JOIN x ON' vs 'JOIN x\n ON'). Pick the option that matches your team's style and stick with it.

Will it minify SQL?

Some builds offer a 'one-line' mode that strips newlines and extra whitespace. Useful for embedding SQL in code as a string literal. Always keep the formatted version in version control - one-line SQL is unreadable for review.