Skip to content
Formatters 7 min read

SQL Formatting Best Practices: Readable Queries That Scale

Learn SQL formatting conventions for SELECT, JOIN, WHERE, and CTEs that make queries readable, maintainable, and reviewable in teams. Includes before/after examples.

ToolsVito Team

Why SQL Formatting Matters

Unlike application code, SQL queries often live in single strings — hard to diff, hard to review, and easy to break. A consistently formatted SQL style reduces review friction, makes bugs visible, and helps new team members understand data logic quickly.

Basic Conventions

Keyword Casing

Two camps: UPPERCASE keywords vs lowercase. Both work. The important thing is consistency within a project. UPPERCASE is the traditional convention and improves visual separation from identifiers:

-- Good (uppercase keywords)
SELECT
    user_id,
    email,
    created_at
FROM users
WHERE status = 'active'
ORDER BY created_at DESC;

-- Also fine (lowercase, but consistent)
select user_id, email
from users
where status = 'active';

One Clause Per Line

Put each major clause on its own line. This makes each part independently skimmable:

-- Bad
SELECT id, name, email FROM users WHERE status = 'active' AND age > 18 ORDER BY name LIMIT 100;

-- Good
SELECT
    id,
    name,
    email
FROM users
WHERE
    status = 'active'
    AND age > 18
ORDER BY name
LIMIT 100;

JOIN Formatting

SELECT
    o.id AS order_id,
    u.email AS customer_email,
    p.name AS product_name
FROM orders o
INNER JOIN users u
    ON o.user_id = u.id
LEFT JOIN order_items oi
    ON oi.order_id = o.id
LEFT JOIN products p
    ON oi.product_id = p.id
WHERE o.status = 'completed'
    AND o.created_at >= '2024-01-01';

Put the ON condition on a new line, indented under the JOIN. This makes it trivial to spot missing or incorrect join conditions.

Common Table Expressions (CTEs)

CTEs (WITH clauses) are the single best tool for making complex SQL readable. Name them like variables — describe what they contain, not what they do:

WITH
active_users AS (
    SELECT id, email, plan_id
    FROM users
    WHERE status = 'active'
        AND last_login_at >= CURRENT_DATE - INTERVAL '90 days'
),

revenue_by_plan AS (
    SELECT
        plan_id,
        SUM(amount) AS total_revenue,
        COUNT(DISTINCT user_id) AS paying_users
    FROM subscriptions
    WHERE status = 'paid'
    GROUP BY plan_id
)

SELECT
    p.name AS plan_name,
    r.paying_users,
    r.total_revenue,
    ROUND(r.total_revenue / NULLIF(r.paying_users, 0), 2) AS arpu
FROM revenue_by_plan r
INNER JOIN plans p ON r.plan_id = p.id
ORDER BY r.total_revenue DESC;

Window Functions

Format the OVER clause across multiple lines for complex windows:

SELECT
    user_id,
    order_date,
    amount,
    SUM(amount) OVER (
        PARTITION BY user_id
        ORDER BY order_date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total,
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_date) AS order_rank
FROM orders;

CASE Expressions

SELECT
    id,
    CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        ELSE 'F'
    END AS grade
FROM test_results;

Subqueries vs CTEs

Prefer CTEs over inline subqueries whenever the subquery is more than one line. CTEs can be read top-to-bottom like a story; nested subqueries force the reader to scan inside-out.

-- Harder to read
SELECT * FROM users WHERE id IN (
    SELECT user_id FROM orders WHERE amount > (
        SELECT AVG(amount) FROM orders
    )
);

-- Easier to read
WITH avg_order AS (
    SELECT AVG(amount) AS avg_amount FROM orders
),
high_value_orders AS (
    SELECT user_id
    FROM orders, avg_order
    WHERE orders.amount > avg_order.avg_amount
)
SELECT * FROM users WHERE id IN (SELECT user_id FROM high_value_orders);

Format SQL Instantly

Use ToolsVito's SQL Formatter to beautify SQL from any dialect (PostgreSQL, MySQL, SQLite, T-SQL) with consistent indentation, keyword casing, and clause alignment — directly in your browser.

Try it now — free, runs in your browser

SQL Formatter

Readable, consistent SQL