SQL is one of the oldest programming languages still in widespread daily use, and readable SQL is an undervalued professional skill. Poorly formatted queries are difficult to understand, hard to debug, and painful to maintain. Well-formatted SQL reads almost like plain English — exactly as its designers intended. This guide covers the conventions and practices that make SQL a pleasure to read.
> Format your data: Whether you are working with JSON API responses or CSV exports from your database, our [JSON Formatter](/tools/json-formatter) and [CSV to JSON Converter](/tools/csv-to-json) help you work with data more efficiently.
Why SQL Formatting Matters
SQL queries in production applications can span dozens of lines with multiple joins, subqueries, CTEs, and conditional logic. A query that fits neatly on screen with consistent indentation is straightforward to understand and modify. The same query written without formatting is genuinely difficult to follow, even for experienced developers.
Poor SQL formatting also makes peer review harder and increases the chance of logic errors going unnoticed.
The Two Schools: UPPERCASE vs. lowercase Keywords
Advertisement
The oldest SQL formatting debate is whether to write SQL keywords in UPPERCASE or lowercase. Both are valid — SQL is not case-sensitive for keywords.
UPPERCASE keywords (SELECT, FROM, WHERE) is the classical convention, still dominant in enterprise environments, textbooks, and professional tools. Keywords stand out visually against table and column names.
lowercase keywords (select, from, where) is increasingly common in modern development, particularly in environments where SQL is embedded in code. IDEs and syntax highlighters provide visual distinction without needing uppercase.
The golden rule: pick one and be consistent throughout your project or team. Mixed case within the same codebase is the worst of both worlds.
Clause-Per-Line Structure
The most impactful structural convention is writing each major SQL clause on its own line:
-- Bad: everything on one line SELECT u.id, u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id WHERE u.active = true ORDER BY o.total DESC LIMIT 10; -- Good: each clause on its own line SELECT u.id, u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id WHERE u.active = true ORDER BY o.total DESC LIMIT 10;
This structure makes it immediately clear what each clause does and makes it easy to add, remove, or comment out individual clauses during development.
Comma Placement: Trailing vs. Leading
Another formatting debate: should commas in column lists go at the end of lines (trailing commas) or the beginning of lines (leading commas)?
Trailing commas look more natural and match conventions in other programming languages. Leading commas make it trivially easy to comment out any column without worrying about trailing commas on the preceding line. Most modern teams use trailing commas; the key is consistency.
Common Table Expressions (CTEs)
CTEs are one of the most powerful SQL features for readability. They let you name and separately define intermediate query steps:
WITH recent_orders AS (
SELECT
user_id,
COUNT(*) AS order_count,
SUM(amount) AS order_total
FROM orders
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY user_id
),
premium_users AS (
SELECT id, name
FROM users
WHERE plan = 'premium'
)
SELECT
pu.name,
ro.order_count,
ro.order_total
FROM premium_users pu
JOIN recent_orders ro ON pu.id = ro.user_id;The CTE version is self-documenting — you can read it like a series of named steps.
Naming Conventions for Tables and Columns
| Element | Convention | Example |
|---|---|---|
| Table names | Plural snake_case | `users`, `orders`, `product_categories` |
| Column names | snake_case | `first_name`, `created_at` |
| Boolean columns | `is_` or `has_` prefix | `is_active`, `has_premium` |
| Timestamps | `_at` suffix | `created_at`, `updated_at`, `deleted_at` |
| Meaningful aliases | Short but readable | `users u` (not `users x`) |
Indentation for Subqueries and Nested Logic
Nested subqueries should be indented relative to their parent context:
SELECT
u.name,
order_counts.total
FROM users u
JOIN (
SELECT
user_id,
COUNT(*) AS total
FROM orders
WHERE status = 'completed'
GROUP BY user_id
) order_counts ON u.id = order_counts.user_id
WHERE u.active = true;For deeply nested queries, CTEs are almost always clearer than nested subqueries. If your subquery exceeds 5–6 lines, refactor it as a CTE.
Comments in SQL
-- Single-line: briefly explain a non-obvious condition WHERE u.deleted_at IS NULL -- Soft delete: exclude deleted users /* Multi-line: explain a complex business rule */
Use comments sparingly for non-obvious logic. If a CTE name or column alias fully explains what it is doing, a comment adds noise rather than clarity.
SQL Formatters and Tooling
Modern editors and database clients include SQL formatters: pgAdmin, DataGrip, Azure Data Studio, and DBeaver all offer formatting. For command-line use, tools like sqlfluff provide linting and formatting that can be integrated into CI pipelines.
For working with the output data from your SQL queries, our [JSON Formatter](/tools/json-formatter) can help when APIs return JSON and our [CSV to JSON Converter](/tools/csv-to-json) handles database exports.
Performance-Aware Formatting
When writing complex queries, structure your SQL to match how you think about the query logically — usually starting with the driving table and adding joins and filters. This often produces queries that are both readable and efficient.
Use EXPLAIN or EXPLAIN ANALYZE (in PostgreSQL) or EXPLAIN (in MySQL) to understand how your formatted queries actually execute, and add appropriate indexes to support your most frequent query patterns.
Frequently Asked Questions
Q: Should SQL keywords be UPPERCASE or lowercase?
Either is correct — SQL is case-insensitive for keywords. What matters is consistency within your team or project. Many modern developers prefer lowercase to reduce visual noise; traditional enterprise environments often use UPPERCASE for clarity.
Q: When should I use a CTE vs. a subquery?
Use a CTE when the same derived dataset is referenced more than once, when the subquery logic is complex enough to benefit from a descriptive name, or when a subquery would be nested more than 2 levels deep. CTEs are dramatically more readable for complex queries.
Q: How do I format SQL automatically?
Use sqlfluff (command-line), pgAdmin's built-in formatter, or DataGrip (JetBrains IDE). Most database clients have a "Format SQL" or "Beautify Query" option. Add sqlfluff to your CI pipeline to enforce consistent SQL formatting across your team.
Q: Is there a standard for SQL indentation?
There is no universal standard — unlike Python (which enforces indentation) or Go (which uses gofmt). The most important thing is consistency. Choose 2 or 4 spaces and enforce it with a linter or formatter.
Conclusion
Readable SQL is a mark of professionalism. Clause-per-line structure, consistent keyword casing, meaningful aliases, and strategic use of CTEs transform complex queries into comprehensible ones. Adopt a style guide for your team and enforce it with tooling — your future self and your colleagues will thank you.