SQL has no enforced formatting standard. A query can be written as one dense line or spread across a hundred readable lines and the database does not care. But the people who read, review, debug, and maintain that query very much do. Consistent formatting is not aesthetic preference — it directly affects how quickly problems are found and how confidently changes are made.
Capitalise Keywords, Lowercase Identifiers
The single most impactful formatting rule: SQL keywords in uppercase, everything else in lowercase. This creates an immediate visual distinction between the language syntax and your data model.
AvoidHow major SQL style guides compare
There is no universal SQL formatting standard. The major public style guides agree on more than they disagree on, but every rule has a counterexample somewhere. The table below shows where four widely-cited guides converge and where they diverge.
| Rule | GitLab Data | dbt Labs | Mozilla | SQLFluff (default) |
|---|---|---|---|---|
| Keyword case | lowercase | lowercase | UPPERCASE | UPPERCASE |
| Identifier case | snake_case | snake_case | snake_case | snake_case |
| Indentation | 4 spaces | 4 spaces | 4 spaces | 4 spaces |
| Comma style | trailing | trailing | trailing | trailing |
| JOIN type | explicit | explicit | explicit | explicit |
| CTEs vs subqueries | CTEs preferred | CTEs preferred | either | not enforced |
| Line length cap | — | ~80 chars | — | 120 chars |
| Trailing semicolon | required | optional | required | configurable |
The lowercase-keywords convention from GitLab Data and dbt Labs is the loudest contemporary dissent against the long-standing UPPERCASE-keyword tradition. Their argument: lowercase reads more like prose, and modern editors handle the visual distinction with syntax highlighting. The counter-argument: in code review tools, email, terminal output, and plain-text diffs, syntax highlighting is not there — and UPPERCASE keywords still help readers parse intent. Pick one position, document it in your repo, and let a linter (SQLFluff being the most popular) enforce it.
One Clause Per Line
Each major clause — SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT — starts on its own line. This makes it immediately obvious which clauses are present and makes adding or removing a clause a single-line change rather than a surgery on a long string.
Indent SELECT Columns
When selecting multiple columns, put each column on its own line indented under SELECT. This makes it easy to add, remove, or comment out a single column without touching other lines.
Indent ON Conditions Under JOIN
The ON condition belongs to the JOIN that precedes it, not to the WHERE clause. Indent it under the JOIN line to make this relationship clear, especially when there are multiple joins.
Use Meaningful Table Aliases
Single-letter aliases (u, o) are fine for short queries, but for complex queries with many joins, use aliases that reflect the table name more clearly. The rule: an alias should make the query easier to read, not shorter to type.
Explicit JOIN Types
Always write the JOIN type explicitly. JOIN alone is an INNER JOIN, but writing it out removes any ambiguity. A future reader (including yourself) should not need to remember whether an unqualified JOIN is inner or outer in your codebase.
WHERE Clause Formatting
For multiple conditions in a WHERE clause, put each condition on its own line with the boolean operator at the start of the line. This makes it easy to add, remove, or comment out a condition.
Subquery Indentation
Subqueries should be indented consistently — the inner query should be indented relative to the outer query's clause it belongs to. Always alias a subquery.
Avoid SELECT *
SELECT * in production code is almost always wrong. It returns columns you do not need (wasting bandwidth), breaks when the table schema changes, and makes it impossible to know what data the query returns without looking at the table definition. Always name the columns you need explicitly.
Frequently Asked Questions
- Does SQL formatting affect query performance?
- No — the database parser ignores whitespace completely. Formatting is purely for human readability. The query engine produces the same execution plan regardless of how the SQL is formatted. The only performance-relevant decisions are in the logic of the query itself, not its visual presentation.
- Should SQL keywords be uppercase or lowercase?
- Uppercase keywords is the strong industry convention, though SQL itself is case-insensitive for keywords. The reason is purely readability — uppercase keywords create an immediate visual distinction between the SQL syntax and your identifiers. Most linters, code review tools, and SQL style guides (SQLFluff, dbt style guide, GitLab SQL style guide) default to uppercase keywords.
- Should I use leading or trailing commas for SELECT columns?
- Both are in common use. Trailing commas (comma at the end of each line) match most programming languages and feel natural. Leading commas (comma at the start of each line) make it easier to comment out the last column without adjusting the line above. The most important rule is to be consistent within a codebase. If your team or ORM generates trailing commas, use trailing commas.
- What is the difference between WHERE and HAVING?
WHEREfilters rows before aggregation — it operates on individual rows and cannot use aggregate functions.HAVINGfilters after aggregation — it operates on grouped results and can use aggregate functions likeSUM(),COUNT(),AVG(). A common pattern:WHEREto pre-filter rows for performance,HAVINGto filter aggregated groups:WHERE status = 'active' GROUP BY user_id HAVING COUNT(*) > 5.- Should I use CTEs (WITH clauses) or subqueries?
- For anything beyond a single inline subquery, prefer a CTE (Common Table Expression) using the
WITHclause. CTEs are named, reusable, and the query reads top-to-bottom in the same order the work happens. Subqueries are fine for one-line filters in aWHEREorFROM, but multi-line subqueries embedded mid-query are harder to follow than the same logic broken out as a CTE. Performance is essentially identical on every modern database — Postgres, MySQL 8+, SQL Server, BigQuery, and Snowflake all inline CTEs unless explicitly materialised. - What is the dbt SQL style guide?
- The dbt Labs SQL style guide is the de-facto standard for analytics SQL in modern data teams. Its main positions are: lowercase keywords (a break from the older UPPERCASE tradition), snake_case identifiers, trailing commas, four-space indentation, explicit
INNER JOINover bareJOIN, and a strong preference for CTEs over nested subqueries. It is the basis for most dbt-templated project styles and is open source on GitHub. - How long should a SQL query be?
- There is no hard limit, but once a query exceeds roughly 30 lines, break it into CTEs. Each CTE should do one thing and carry a name that says what it does —
active_users,orders_last_30_days. A 200-line monolithic query with seven joins and three subqueries is correct but unmaintainable; the same logic as five named CTEs is reviewable in five chunks. Aim for line length under 120 characters so the query fits in a side-by-side diff without horizontal scrolling.