Document Workflow
Format SQL for code review and verify query behavior
A practical dialect-first workflow for formatting SQL, reviewing the semantic diff, and proving behavior in the actual database before deployment.
Written and tested by SimpleWebUtilsPublished: Reviewed:
How this workflow was checked
This check paired the exact “Format a grouped query, then verify it against the review schema” input with SQL Formatter. We followed “Identify the target database, version, and execution context”, captured the result after “Format manually with explicit, reproducible settings”, and compared it with the example while treating “Using the generic dialect for vendor syntax” and “Removing syntax to satisfy the formatter” as explicit boundary questions.
The formatter exposed the JOIN predicate, active filter, grouping, and descending alias order on separate reviewable clauses without changing string literals or query structure.
Problem
A long SQL statement is hard to review, so teams often paste it into a generic formatter and treat any clean output as proof that the query is correct. That shortcut combines three different jobs: laying out tokens, validating vendor syntax, and proving behavior against a particular schema and dataset. A whitespace formatter can recognize enough structure to place SELECT, JOIN, WHERE, GROUP BY, and ORDER BY, yet still accept an incomplete clause, miss a server-version rule, know nothing about tables or column types, and never evaluate permissions, locks, cardinality, indexes, time zones, collation, NULL behavior, transaction boundaries, or migration order. Selecting the wrong grammar can also reject valid PostgreSQL casts, T-SQL bracketed identifiers, MySQL backticks, or BigQuery names. Stored procedures and custom delimiters add another language layer that a query formatter may not support. Meanwhile, copied SQL can contain credentials, tenant identifiers, personal data, private URLs, or production literals that should not enter clipboard history, extensions, screenshots, or downloaded files. The objective is therefore narrower and more reliable: use formatting to create a reviewable candidate, preserve the original and exact settings, fail clearly at unsupported boundaries, compare a semantic diff, and require the database and application tests to prove everything the formatter cannot.
When to use this
- A one-line query, CTE, join chain, report query, or non-routine multi-statement script must be made readable before a pull request or incident review.
- A PostgreSQL, MySQL, SQLite, SQL Server, Oracle query statement, or BigQuery query produces different formatting or parse results and the selected dialect must be isolated.
- A generated or copied query needs a stable fixture for documentation or tests without changing identifiers, literals, comments, parameters, or semicolons.
- A formatting-only change must be separated from schema, performance, permission, migration, and application behavior checks.
- A team wants to pin formatter version and settings in CI after manually verifying representative edge cases and rollback conditions.
Steps
- Step 1
Identify the target database, version, and execution context
Record the database product and version, client or driver, parameter style, schema or search path, transaction mode, and whether the text is a query, migration, generated fragment, stored routine, or template. Choose Standard SQL only when vendor-specific syntax is absent. For PostgreSQL casts and dollar parameters, T-SQL bracketed identifiers, MySQL backticks, PL/SQL query statements, SQLite functions, or BigQuery paths, select the matching grammar explicitly.
- Step 2
Preserve the source and redact sensitive values
Keep the original in version control or a separate fixture and record a checksum when exact bytes matter. Replace passwords, tokens, personal data, tenant identifiers, private hostnames, proprietary literals, and production keys with representative non-secret values before using a browser, clipboard, screenshot, or download. Do not change placeholders or quoting rules while redacting.
- Step 3
Format manually with explicit, reproducible settings
In SQL Formatter select the dialect, keyword case, and 2, 4, or 8-space indentation, then run Manual mode. Keep the input within 1,000,000 UTF-8 bytes, 20,000 lines, and 100,000 UTF-8 bytes per line. Record sql-formatter 15.8.2 and the exact options so another reviewer or CI can reproduce the same artifact.
- Step 4
Stop at parse and unsupported-language boundaries
Use a reported line and column to check the selected dialect, unmatched quotes or parentheses, template syntax, and unsupported tokens. Do not delete source until output appears. Stored procedures, stored functions, triggers, and custom DELIMITER scripts are outside this browser formatter contract; move those to the database vendor's parser, IDE, or migration tool instead.
- Step 5
Review a semantic diff, not only the visual layout
Compare source and candidate with whitespace-aware and whitespace-ignored views. Confirm identifiers, quoted names, literals, placeholders, casts, operators, comments, optimizer hints, semicolons, and statement order are retained. Pay special attention to comments consumed by build tools, generated fragments whose surrounding whitespace matters, and accidental keyword or data-type case changes in quoted text.
- Step 6
Prove behavior in the real database and application
Parse or prepare the candidate with the correct server version and schema, then run it against safe representative data. Compare result rows and types, errors, affected-row counts, permissions, transactions, locking, and rollback. Use EXPLAIN or the vendor plan tool when performance matters, and run application, migration, integration, timezone, collation, NULL, and regression tests before approving the change.
- Step 7
Automate the verified style and rollback path
After representative queries pass, pin the formatter version and configuration in the repository, add fixtures for every dialect and unsupported boundary, and make CI detect formatting drift without silently rewriting production migrations. Keep the original migration history, review generated diffs, and define the exact condition and command for rollback.
Example
Format a grouped query, then verify it against the review schema
Input
select c.id, c.name, count(o.id) as order_count from customers c left join orders o on o.customer_id = c.id and o.status = 'paid' where c.active = true group by c.id, c.name having count(o.id) > 2 order by order_count desc;Output
SELECT
c.id,
c.name,
count(o.id) AS order_count
FROM
customers c
LEFT JOIN orders o ON o.customer_id = c.id
AND o.status = 'paid'
WHERE
c.active = TRUE
GROUP BY
c.id,
c.name
HAVING
count(o.id) > 2
ORDER BY
order_count DESC;Common mistakes
Using the generic dialect for vendor syntax
A generic grammar can reject valid vendor tokens or lay them out poorly. Select the database first and reproduce errors with a minimal non-secret fixture.
Calling formatted SQL validated SQL
Formatting does not resolve a schema, compile a stored routine, inspect permissions, execute a statement, compare results, or prove an execution plan. Keep those gates explicit.
Removing syntax to satisfy the formatter
Deleting casts, hints, template markers, delimiters, or routine syntax can produce attractive but different SQL. Preserve the source and move unsupported input to the appropriate vendor tool.
Reviewing only a whitespace-ignored diff
A whitespace-ignored view can hide lost comments, changed quoted text, statement order, or semicolons. Use both exact and semantic comparisons.
Running the candidate directly in production
Use an isolated database with representative schema and safe data first. Verify plans, permissions, transactions, locks, migrations, tests, and rollback before any production execution.
FAQ
Why does the same SQL format differently by dialect?
Each grammar recognizes different quoted identifiers, parameters, operators, data types, functions, and reserved words. The chosen dialect changes token classification and layout, so record it as part of the artifact.
Can a formatter prove SQL syntax is valid?
No. It can report some parse failures, but its grammar and completeness checks are not the target database server. Only the correct server version, schema, client, and execution context can validate the full statement.
Should comments survive SQL formatting?
This formatter retains supported line and block comment tokens, but their placement can move. Compare the exact diff, especially for optimizer hints, migration directives, license text, and comments consumed by other tools.
How should I handle generated SQL or templates?
Format the fully rendered, redacted query when possible. Template markers may not belong to the SQL grammar, and formatting a fragment without its surrounding context can change whitespace contracts. Keep generation tests and compare the final prepared statement separately.
When should SQL formatting run in CI?
After the team has pinned a version and settings, reviewed representative queries for every supported dialect, defined exclusions for routines and templates, and ensured CI reports drift without rewriting migration history unexpectedly.
What evidence belongs in a formatting-only pull request?
Include database and version, source role, redaction note, formatter version and settings, exact and semantic diffs, parser or prepare result, representative result comparison, EXPLAIN when relevant, application and migration tests, permission and transaction checks, and rollback criteria.