# Opsdeck SQL Formatter & Linter > Format SQL and catch UPDATE/DELETE without WHERE, SELECT * in views and cross joins. 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. Part of usefulweb.app (https://usefulweb.app/). Part of [Opsdeck](https://opsdeck.usefulweb.app/) (ownerApp: opsdeck). Results are deterministic calculations from the inputs and the listed assumptions; the API returns exactly what the web page shows. ## Use it - Human interface: https://opsdecksqlformatter.usefulweb.app/ (interactive tool at https://opsdecksqlformatter.usefulweb.app/tool) - JSON API: POST https://opsdecksqlformatter.usefulweb.app/api/v1/calculate with a JSON object of inputs (schema: https://opsdecksqlformatter.usefulweb.app/api/v1/tool) - OpenAPI: https://opsdecksqlformatter.usefulweb.app/openapi.json - MCP (Streamable HTTP): https://opsdecksqlformatter.usefulweb.app/mcp - tool `opsdeck_sql_formatter` ## Inputs - sql (textarea): SQL - keywordCase (select): Keyword case - indent (integer): Indent width ## Method - 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.