Ctrl K

How to Format SQL for Readable, Reviewable Queries

beginner TheToolSera Team 6 min read Updated 15 May 2026

SQL is written once and read many times. Formatting does not change the execution plan by a single millisecond, but it decides whether the next person can review your query in thirty seconds or thirty minutes.

Before and after

As written
select c.id,c.name,sum(o.total) as revenue from customers c join orders o on o.customer_id=c.id where o.created_at>='2026-01-01' and o.status='paid' group by c.id,c.name having sum(o.total)>1000 order by revenue desc limit 20;
Formatted
SELECT
    c.id,
    c.name,
    SUM(o.total) AS revenue
FROM customers AS c
JOIN orders   AS o ON o.customer_id = c.id
WHERE o.created_at >= '2026-01-01'
  AND o.status = 'paid'
GROUP BY c.id, c.name
HAVING SUM(o.total) > 1000
ORDER BY revenue DESC
LIMIT 20;

Same query, same plan. The second version lets you scan the joins, spot the filters and see the aggregation boundary without parsing the text in your head.

Rules that carry most of the benefit

  • Put each major clause — SELECT, FROM, JOIN, WHERE, GROUP BY, ORDER BY — on its own line
  • One column per line in the select list once there are more than two or three
  • Uppercase keywords, lowercase identifiers, so structure and data names are visually distinct
  • Indent AND/OR conditions under WHERE so boolean grouping is obvious
  • Always alias tables and always qualify columns in a multi-table query
  • Write the join condition on the same line as the join when it is short

Leading vs trailing commas

Leading commas make add/remove diffs cleaner
SELECT
    c.id
  , c.name
  , c.email
FROM customers AS c;

Both conventions are fine. What matters is that your team picks one and a formatter enforces it, so diffs show real changes rather than punctuation churn.

Long queries: use CTEs

WITH paid_orders AS (
    SELECT customer_id, total
    FROM orders
    WHERE status = 'paid'
      AND created_at >= '2026-01-01'
),
revenue AS (
    SELECT customer_id, SUM(total) AS revenue
    FROM paid_orders
    GROUP BY customer_id
)
SELECT c.name, r.revenue
FROM revenue AS r
JOIN customers AS c ON c.id = r.customer_id
ORDER BY r.revenue DESC;

A nested subquery three levels deep is almost always clearer as named CTEs. Each step gets a name, and you can run any step in isolation while debugging.

SQL Formatter

Paste a query and get consistent casing, indentation and clause layout instantly.

Try SQL Formatter

Common mistakes

SELECT * in production code

It breaks when columns change, moves more data than needed and hides which fields are actually used.

Implicit joins in the WHERE clause

Comma joins hide the join condition among filters. Use explicit JOIN ... ON.

Inconsistent casing within a file

Mixed Select/SELECT/select forces the reader to re-tune constantly. Let a formatter decide.

Formatting only when a review is due

Format on save, so diffs never mix reformatting with logic changes.

Formatting is not optimisation. If a query is slow, read the execution plan — a formatter changes readability, never performance.

Frequently asked questions

Does formatting SQL affect performance?

No. Whitespace and casing are discarded by the parser, so the execution plan is identical.

Should SQL keywords be uppercase?

It is the most common convention because it separates keywords from identifiers at a glance, but consistency matters more than the choice itself.

How should I format very long queries?

Break them into named CTEs. Each step becomes readable and independently testable.

Can I format SQL for a specific dialect?

Yes — good formatters understand dialect-specific keywords for MySQL, PostgreSQL, T-SQL and others so nothing is misinterpreted.

Put this into practice

SQL Formatter runs entirely in your browser — no upload, no account, no limits.

Open SQL Formatter

Related tools

Related guides

All guides

Explore related topics