Premium apps Part of Opsdeck

Opsdeck SQL Formatter & Linter

Format SQL and catch UPDATE/DELETE without WHERE, SELECT * in views and cross joins.

spaces

Try an example: Report query with joins, grouping and a date range · Lint: dangerous statements · Lower-case keywords, 4-space indent, a CTE and CASE

More about this tool

How it works

Formats SQL statements with clauses on their own lines, one select item per line, indented AND/OR conditions, subqueries and CREATE TABLE bodies, and keywords in the case you choose; comments are kept and formatting twice changes nothing. The linter flags UPDATE or DELETE without WHERE, SELECT * in views, comma joins without a condition, “= NULL”, NOT IN with a subquery, leading-wildcard LIKE, destructive statements and INSERT without a column list. It is the formatter of the Opsdeck Database desk.

  • The SQL is split into tokens (keywords and names, quoted names, strings including E'…' and $tag$…$tag$, numbers, operators, comments) and into statements at semicolons outside parentheses and BEGIN … END blocks.
  • Each statement is written again from its tokens: main clauses (SELECT, FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, UNION, INSERT INTO, VALUES, UPDATE, SET, DELETE FROM, RETURNING) start a line; select items get one line each; AND/OR of WHERE, ON and HAVING are indented (the AND of BETWEEN stays); subqueries and CREATE TABLE bodies are indented; function calls and IN lists stay inline. Since the layout depends only on the tokens, formatting the output again returns it unchanged.
  • The linter works on the same tokens per query level: missing WHERE in UPDATE/DELETE, * in the select list of a view, commas between tables in FROM (Cartesian product when there is no WHERE), = / <> NULL in conditions (but not in SET assignments), NOT IN (SELECT …), LIKE patterns that start with % or _, TRUNCATE/DROP/DROP COLUMN, and INSERT without a column list.

Sources

Part of Opsdeck

  • Opsdeck Developer & ops workbench

    One deck for CI failures, cron, traces, k8s events, API diffs, query plans and Terraform.

    Open Opsdeck

Related tools

How to use the Opsdeck SQL Formatter & Linter

Format SQL into a consistent layout and find statements that change every row, cross joins, SELECT * in views and NULL comparison mistakes.

What it is for

SQL arrives in every shape: one long line from a log, a query copied from an ORM, a migration written by three people. This tool rewrites it in one consistent layout, so it is easy to read and diffs stay small, and it checks the statements for patterns that cause real incidents, such as an UPDATE without WHERE.

It is a formatter and a pattern linter, not a database. It does not know your tables, so it cannot tell whether a column exists or a query is slow; for plans use the Query Plan Visualizer.

Worked example

The second example pastes five short statements in lower case: an update accounts set balance = 0, a delete from sessions, a select * from orders, customers, a view defined with select * and a query with closed_at = null, not in (select …) and like '%crash'.

The tool answers 5 statements formatted; the linter found 3 errors, 2 warnings and 3 notes.

The errors are the UPDATE and the DELETE without WHERE, which change every row, and the comma join with no condition: "the result is every combination of rows (a Cartesian product)". The warnings are SELECT * in the view, whose column list freezes at creation time in PostgreSQL and MySQL, and closed_at = NULL, which is never true. The notes are the plain SELECT *, the NOT IN subquery, which returns no rows at all if the subquery returns a NULL, and the leading-wildcard LIKE, which cannot use an ordinary index.

In the formatted output each clause starts its own line (SELECT, FROM, WHERE), select items get one line each, the second and third conditions start with an indented AND, and the subquery is indented inside its parentheses.

How to read the result

  • Formatted SQL: copy it back into your editor. Names, string literals and comments are never changed, only whitespace and keyword case.
  • Lint findings: level, rule name, statement number, line and an explanation. Errors are always worth fixing; warnings almost always; notes depend on context.
  • The summary counts the findings per level; errors are repeated as warnings at the top of the result.

Tips and common mistakes

  • Formatting is idempotent: running the output through the tool again changes nothing, so it is safe in a pre-commit step.
  • Choose lower-case keywords if your team writes them that way; the layout stays the same.
  • UPDATE t SET x = NULL is an assignment and is not flagged; only comparisons in WHERE, ON, HAVING and CASE WHEN are.
  • If a full-table update is really intended, write WHERE true so readers see that it is deliberate.
  • The AND inside BETWEEN … AND … stays on its line; only logical AND/OR start new lines.

FAQ

Which dialects does it format?

The tokenizer understands PostgreSQL, MySQL and SQLite syntax, including E'…' and $$…$$ strings, backtick and bracket names and :: casts. Vendor-specific procedural code is formatted only roughly.

Does it reorder or rewrite my query?

No. It changes whitespace and keyword case only; the order of tokens stays exactly as you wrote it.

Why is SELECT * only a note outside views?

In ad-hoc queries it is often fine. In application code and especially in views it hides which columns you depend on, so the view rule is stricter.

Can it check many files at once?

Paste several statements separated by semicolons; each one is formatted and linted, and findings name the statement number and line.

Guide last updated:

For scripts and AI agents

  • JSON API: POST https://opsdecksqlformatter.usefulweb.site/api/v1/calculate (same calculation as this page)
  • Interface description: OpenAPI 3.1 · AI guide: llms.txt
  • MCP server (Streamable HTTP): https://opsdecksqlformatter.usefulweb.site/mcp · tool name opsdeck_sql_formatter
Example request
curl -s -X POST https://opsdecksqlformatter.usefulweb.site/api/v1/calculate \
  -H 'content-type: application/json' \
  -d '{}'
Feedback · ideas & bug reports welcome