Raw SQL is often painful to read. If you’ve ever received a stored procedure as a single wall of text, or tried to debug a dynamically constructed query from an ORM log, you know the feeling:
select u.id,u.name,u.email,o.total,o.created_at from users u inner join orders o on u.id=o.user_id where u.active=1 and o.total>100 order by o.created_at desc
A well-formatted equivalent is immediately understandable:
SELECT
u.id,
u.name,
u.email,
o.total,
o.created_at
FROM
users u
INNER JOIN orders o ON u.id = o.user_id
WHERE
u.active = 1
AND o.total > 100
ORDER BY
o.created_at DESC
Same query. Completely different reading experience. This guide covers what a good SQL formatter does, why dialect selection matters, and how to fit it into your actual workflow.
Why Dialect Matters
SQL is nominally standardized, but in practice every database engine has its own syntax quirks, reserved words, and formatting expectations. A formatter that doesn’t account for dialect will produce output that’s either wrong or looks alien to the team working on that database.
Here are some concrete examples of where dialects diverge:
Identifier quoting
- T-SQL (SQL Server): Uses square brackets —
[column_name] - MySQL: Uses backticks —
`column_name` - PostgreSQL / SQLite / Standard SQL: Uses double quotes —
"column_name"
If you’re formatting T-SQL with a MySQL-aware formatter, you get backticks everywhere — which is technically valid in some contexts but wrong for SQL Server.
Boolean literals
- PostgreSQL / SQLite:
TRUEandFALSEare keywords - MySQL:
TRUEandFALSEwork but are aliases for1and0 - T-SQL: No native boolean — uses
1and0, orBIT
String concatenation
- T-SQL:
first_name + ' ' + last_name - PostgreSQL / SQLite:
first_name || ' ' || last_name - MySQL:
CONCAT(first_name, ' ', last_name)
Top vs Limit vs Fetch
- T-SQL:
SELECT TOP 10 ... - MySQL / PostgreSQL / SQLite:
SELECT ... LIMIT 10 - Standard SQL 2008+:
SELECT ... FETCH FIRST 10 ROWS ONLY
A formatter that knows your dialect will uppercase these correctly, preserve the syntax you intended, and not rewrite constructs that are valid in your target engine.
The Six Supported Dialects
The ByteKiln SQL formatter supports:
| Dialect | Common use |
|---|---|
| Standard SQL | Generic / cross-database formatting |
| MySQL | MySQL and MariaDB projects |
| PostgreSQL | Postgres-heavy backends, Supabase, Railway |
| T-SQL | SQL Server, Azure SQL, SSMS |
| PL/SQL | Oracle database |
| SQLite | Embedded databases, mobile, testing |
Select the dialect that matches your target database. The formatting engine uses dialect-specific keyword sets and indentation conventions.
What Gets Formatted
A full-featured SQL formatter handles these structural elements:
Keywords — SELECT, FROM, WHERE, JOIN, GROUP BY, ORDER BY, etc. are uppercased and placed on their own lines or with consistent indentation.
Indentation — Nested subqueries, CTEs, and multi-level CASE expressions are indented proportionally to their nesting depth.
Comma placement — Leading vs trailing comma style is applied consistently. Many teams have a preference (leading commas make it easy to comment out a column without touching the previous line).
Clause spacing — Each major clause (WHERE, JOIN, HAVING) starts on its own line with consistent alignment.
Function calls — Preserved as-is but spaced correctly.
Reading the Size Stats
After formatting, the tool shows before/after character counts and the size change percentage. For most SQL, formatting increases size (whitespace is added). But this is useful to confirm the formatter didn’t silently drop content.
Where size stats are more directly useful: when you paste minified or aggressively compressed SQL from an ORM log or a monitoring tool, and you want to confirm the full statement was parsed and reproduced.
Practical Workflows
Reviewing a migration script
Migration scripts often accumulate formatting debt — different developers write in different styles. Before committing a migration, run it through the formatter to normalize style. The SQL is equivalent, but the diff in your version control will be easier for reviewers to read.
Debugging ORM-generated queries
ORMs like Entity Framework, Hibernate, or SQLAlchemy log queries in a compressed, often hard-to-read form. Copy the logged query, paste it into the formatter, select the appropriate dialect, and get a readable version. Now you can see what join is happening, whether the WHERE clause is what you expected, and whether an index-friendly pattern is being used. ORM queries often return JSON-typed columns alongside relational data — the JSON Formatter handles those payloads if you need to inspect them in the same session.
Writing ad-hoc queries
When writing complex queries by hand — especially those with CTEs, nested subqueries, or window functions — start formatted. Formatting helps you catch mismatched parentheses, incorrect join conditions, and missing clauses before you run the query.
Code reviews
Unformatted SQL in a code review is hard to read and easy to misread. If you receive a PR with raw, compressed SQL, format it locally to understand the logic before leaving a review comment.
Common SQL Formatting Patterns
CTEs (Common Table Expressions)
WITH
recent_orders AS (
SELECT
user_id,
SUM(total) AS total_spent
FROM
orders
WHERE
created_at > '2026-01-01'
GROUP BY
user_id
)
SELECT
u.name,
ro.total_spent
FROM
users u
INNER JOIN recent_orders ro ON u.id = ro.user_id
WHERE
ro.total_spent > 500
ORDER BY
ro.total_spent DESC
Window functions
SELECT
name,
department,
salary,
RANK() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS salary_rank
FROM
employees
CASE expressions
SELECT
order_id,
CASE
WHEN status = 'shipped' THEN 'In transit'
WHEN status = 'delivered' THEN 'Complete'
WHEN status = 'cancelled' THEN 'Cancelled'
ELSE 'Pending'
END AS status_label
FROM
orders
Proper indentation of these structures makes the logic readable without comments.
What the Formatter Doesn’t Do
Execution — No database connection is made. The formatter works on text only. Your query is never run.
Semantic validation — It won’t tell you if a column doesn’t exist, if the JOIN condition is wrong, or if you have a logic error. For that, you need a real database.
Query optimization — Formatting doesn’t suggest indexes, rewrite inefficient patterns, or analyze query plans. It’s a presentation tool, not a query analyzer.
SQL Style Preferences
Formatting is partly about readability and partly about team conventions. Two common styles:
Trailing commas (common in many teams):
SELECT
id,
name,
email
Leading commas (easy to comment out a column):
SELECT
id
, name
, email
Neither is wrong. The value of a formatter is picking one and applying it everywhere.
If you’re working with DDL rather than queries, the JSON to SQL guide covers inferring table schemas from JSON objects, and the C# to SQL guide handles the entity class → CREATE TABLE translation — both produce output that’s worth running through the formatter before committing.
The SQL formatter’s job is simple but high-value: take any SQL regardless of how it arrived, and make it readable in the context of the database you’re targeting. Paste it in, pick your dialect, and move on.