FmtDev
Language
Back to blog
March 25, 2026

SQL Formatting Best Practices: Write Clean Queries That Scale

Learn how to format SQL queries for readability, maintainability, and team collaboration. Covers indentation, naming conventions, JOIN formatting, subquery structure, and common mistakes.

Why SQL Formatting Matters

SQL is one of the most widely used languages in software development. Every backend developer, data analyst, and DevOps engineer writes SQL queries regularly.

But most SQL queries in production codebases look like this:

SELECT u.id,u.name,u.email,o.total,o.created_at FROM users u JOIN orders o ON u.id=o.user_id WHERE o.total>100 AND u.active=1 ORDER BY o.created_at DESC LIMIT 50;

This works. The database doesn't care about formatting. But humans do.

When a query is one long line, it is:

  • hard to read during code review
  • hard to debug when something breaks
  • hard to modify when requirements change
  • impossible to understand at 2 AM during an incident

Clean SQL formatting is not about aesthetics. It is about reducing the cost of understanding code.

The Basics: One Clause Per Line

The single most impactful formatting rule is: put each major SQL clause on its own line.

SELECT
  u.id,
  u.name,
  u.email,
  o.total,
  o.created_at
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.total > 100
  AND u.active = 1
ORDER BY o.created_at DESC
LIMIT 50;

Same query. Same result. But now you can instantly see:

  • what columns are selected
  • which tables are joined
  • what conditions are applied
  • how results are ordered

Column Lists

When selecting multiple columns, put each on its own line:

-- Bad
SELECT id, name, email, created_at, updated_at, status FROM users;

-- Good
SELECT
  id,
  name,
  email,
  created_at,
  updated_at,
  status
FROM users;

This makes it easy to:

  • add or remove columns
  • comment out a single column for debugging
  • see exactly what data is being retrieved

JOIN Formatting

JOINs are where queries get complex. Clear formatting prevents confusion:

-- Bad
SELECT u.name,o.total,p.name FROM users u JOIN orders o ON u.id=o.user_id JOIN products p ON o.product_id=p.id WHERE o.status='completed';

-- Good
SELECT
  u.name,
  o.total,
  p.name AS product_name
FROM users u
JOIN orders o
  ON u.id = o.user_id
JOIN products p
  ON o.product_id = p.id
WHERE o.status = 'completed';

Rules for JOINs:

  • each JOIN gets its own line
  • the ON condition is indented below the JOIN
  • use explicit JOIN types (INNER JOIN, LEFT JOIN) instead of just JOIN when the type matters
  • alias tables with short meaningful names

WHERE Clauses

For multiple conditions, indent each condition:

-- Bad
WHERE status='active' AND created_at>'2025-01-01' AND total>100 AND country IN ('US','UK','FR')

-- Good
WHERE status = 'active'
  AND created_at > '2025-01-01'
  AND total > 100
  AND country IN ('US', 'UK', 'FR')

For complex logic with OR, use parentheses clearly:

WHERE status = 'active'
  AND (
    country = 'US'
    OR country = 'UK'
  )
  AND total > 100

Subqueries

Subqueries are the hardest part to format. The key is consistent indentation:

SELECT
  u.name,
  u.email,
  order_summary.total_spent
FROM users u
JOIN (
  SELECT
    user_id,
    SUM(total) AS total_spent
  FROM orders
  WHERE status = 'completed'
  GROUP BY user_id
) AS order_summary
  ON u.id = order_summary.user_id
WHERE order_summary.total_spent > 1000
ORDER BY order_summary.total_spent DESC;

Rules:

  • indent the subquery body
  • close the parenthesis at the same level as the opening keyword
  • always alias subqueries with meaningful names

Common Table Expressions (CTEs)

For complex queries, CTEs are cleaner than nested subqueries:

WITH active_users AS (
  SELECT
    id,
    name,
    email
  FROM users
  WHERE status = 'active'
    AND last_login > '2025-01-01'
),
user_orders AS (
  SELECT
    user_id,
    COUNT(*) AS order_count,
    SUM(total) AS total_spent
  FROM orders
  WHERE status = 'completed'
  GROUP BY user_id
)
SELECT
  au.name,
  au.email,
  uo.order_count,
  uo.total_spent
FROM active_users au
JOIN user_orders uo
  ON au.id = uo.user_id
WHERE uo.total_spent > 500
ORDER BY uo.total_spent DESC;

CTEs make complex queries readable by breaking them into named, logical steps.

Naming Conventions

Consistent naming prevents confusion:

| Element | Convention | Example | |---|---|---| | Tables | lowercase, plural | users, orders, products | | Columns | lowercase, snake_case | created_at, user_id, total_amount | | Aliases | short, meaningful | u for users, o for orders | | CTEs | descriptive snake_case | active_users, monthly_revenue | | SQL keywords | UPPERCASE | SELECT, FROM, WHERE, JOIN |

The most important rule: be consistent. Pick a convention and use it everywhere.

INSERT and UPDATE Formatting

-- INSERT
INSERT INTO users (
  name,
  email,
  status,
  created_at
) VALUES (
  'Alice',
  'alice@example.com',
  'active',
  NOW()
);

-- UPDATE
UPDATE users
SET
  status = 'inactive',
  updated_at = NOW()
WHERE last_login < '2024-01-01'
  AND status = 'active';

Comments in SQL

Use comments to explain why, not what:

-- Bad comment (explains what)
-- Select users where status is active
SELECT * FROM users WHERE status = 'active';

-- Good comment (explains why)
-- Only include active users to exclude 
-- soft-deleted accounts from the report
SELECT * FROM users WHERE status = 'active';

Formatting Tools

Manually formatting every query is tedious. Use a formatter to do the heavy lifting, then adjust as needed.

When using an online SQL formatter, be careful about what data you paste. If your query contains real table names, column names, or business logic, you may be exposing your database schema to a third-party server.

Use a formatter that runs entirely in your browser so your queries never leave your machine.

The FmtDev SQL Formatter processes everything locally. Your SQL never leaves your browser.

SQL Formatting Checklist

  1. One clause per line — SELECT, FROM, JOIN, WHERE, ORDER BY, LIMIT
  2. One column per line in SELECT lists
  3. Indent conditions under WHERE and ON
  4. Explicit JOIN types — write INNER JOIN or LEFT JOIN, not just JOIN
  5. Meaningful aliasesu for users, not t1
  6. UPPERCASE keywords — SELECT, FROM, WHERE, JOIN
  7. lowercase identifiers — table names, column names
  8. CTEs over subqueries for complex logic
  9. Comments explain why, not what
  10. Format locally — never paste proprietary SQL into online tools

Related Articles

Related Tool

Ready to use the Offline SQL Formatter (No Server Logs) tool? All execution is 100% local.

Open Offline SQL Formatter (No Server Logs)