Unformatted SQL is where bugs hide
ORMs generate SQL that is logically correct but visually opaque. A query that takes 8 seconds might be doing a full table scan because of a missing index, or joining in the wrong order, or applying a WHERE filter after an aggregation when HAVING was needed. None of these are obvious in a 400-character single-line string. Formatted, they're visible in 10 seconds.
I described a real debugging session in SQL Formatting as a Debugging Tool — where formatting an ORM-generated query immediately revealed a LEFT JOIN that should have been an INNER JOIN, causing thousands of extra rows to be loaded and then filtered in application code. The fix was one word.
Three bugs that formatting makes instantly visible
- Wrong JOIN typeA LEFT JOIN returns all rows from the left table, including rows with no match on the right — those get NULL values. An INNER JOIN returns only matched rows. ORMs sometimes generate LEFT JOINs when INNER was intended (or vice versa). When formatted, the JOIN keyword is on its own line and easy to spot and change.
- WHERE vs HAVINGWHERE filters rows before aggregation; HAVING filters after. Using WHERE on an aggregated column causes an error; using HAVING when WHERE was intended causes incorrect counts. Formatted SQL puts these on separate lines with clear indentation of the conditions below each.
- N+1 patternsA subquery in the SELECT list that references the outer query runs once per row — the N+1 problem. Formatted SQL makes correlated subqueries visible as indented blocks inside each SELECT column, not buried in a flat string.
How it formats — and what dialect to pick
The formatter uses the sql-formatter library (MIT license) to parse and re-indent SQL according to a consistent style. Dialect selection matters: PostgreSQL uses :: for casting while MySQL uses CAST(x AS type). BigQuery uses backtick identifiers. Pick the dialect that matches your database so the formatter handles the edge cases correctly.
All formatting runs in the browser — your SQL, which may contain table names, column data, or proprietary business logic, never leaves your device.
SQL dialect differences — PostgreSQL vs MySQL vs T-SQL vs BigQuery
The formatter produces ANSI-compatible SQL that works across dialects for standard queries. Here are the key differences you'll need to handle manually when porting queries between databases:
| Feature | PostgreSQL | MySQL | T-SQL (SQL Server) | BigQuery |
|---|---|---|---|---|
| String quotes | Single '' | Single '' or double "" | Single '' | Single '' |
| Identifier quoting | "double_quotes" | `backticks` | [brackets] | `backticks` |
| Top N rows | LIMIT n | LIMIT n | TOP n (before SELECT) | LIMIT n |
| String concat | || or CONCAT() | CONCAT() or concat (no ||) | '+' or CONCAT() | CONCAT() or || |
| Current timestamp | NOW() or CURRENT_TIMESTAMP | NOW() or CURRENT_TIMESTAMP | GETDATE() or GETUTCDATE() | CURRENT_TIMESTAMP |
| Boolean literal | TRUE / FALSE | TRUE/FALSE or 1/0 | No bool — use 1/0 or BIT | TRUE / FALSE |
| Auto-increment | SERIAL or GENERATED ALWAYS | AUTO_INCREMENT | IDENTITY(1,1) | No native auto-increment |
