SQL Formatter
Format and beautify SQL for MySQL, PostgreSQL, SQL Server, Oracle and more.
Paste or open a query to lay it out one clause per line, with keywords in the case you choose, or minify it onto as few lines as it takes. Pick your database's dialect so its quoting, placeholders and keywords read correctly. When the formatter cannot read the SQL, the message names the line and column, and the line is marked in the input.
It runs in your browser, so nothing you paste or open is sent anywhere.
Options
- Dialect — Standard SQL (the default) and MySQL, PostgreSQL, SQL Server (T-SQL), Oracle PL/SQL, SQLite, MariaDB, Google BigQuery, Snowflake, DuckDB, Amazon Redshift, Apache Hive, Apache Spark, ClickHouse, Couchbase N1QL, IBM Db2, IBM Db2 for i (experimental), SingleStoreDB, TiDB, Trino and Presto.
- Format — Pretty puts each clause on its own line and indents what belongs to it. Minified collapses the whitespace between tokens to one space, or none beside brackets, commas and semicolons. Line comments keep the line break after them.
- Indent — 2 spaces (the default), 4 spaces or a tab.
- Keyword case — Preserve, UPPER (the default) or lower. It covers function names and data types as well; table and column names keep their case.
- AND / OR position — at the start of each condition line (the default), or at the end of the line before.
- Blank lines — between statements, 1 to 5.
- Template placeholders — reads
{name}and dbt's{{ ref('orders') }}as values, so templated SQL formats instead of failing. - Remove comments — for Minified. Optimizer hints such as
/*+ INDEX(t i) */and MySQL's/*! … */comments stay, because the database reads them.
The dialect matters because databases write the same things differently. SQL Server quotes names in brackets, [Order ID]; MySQL uses backticks; PostgreSQL wraps function bodies in $$ … $$, and reads # as an operator where MySQL starts a comment. Placeholders differ too: ? in MySQL, $1 in PostgreSQL, @name in SQL Server, :name in Oracle. Standard SQL reads only what most databases share, so when it reports an error, the right dialect often formats the query.
Scripts for SQL Server can hold GO lines, and MySQL scripts can change the statement delimiter with DELIMITER. Both are commands for the client, not SQL. With those dialects chosen, the lines are kept as written on lines of their own, and after DELIMITER // each statement ends at //. Download saves the output as <name>.formatted.sql, or formatted.sql for pasted SQL.
Examples
Joins with conditions
- Input, MySQL, default options
- select o.id, c.name, sum(i.qty * i.price) as total from orders o join customers c on c.id = o.customer_id left join items i on i.order_id = o.id where c.active = 1 and (o.placed_at >= '2026-01-01' or o.status = 'open') group by o.id, c.name
- Pretty
SELECT o.id, c.name, SUM(i.qty * i.price) AS total FROM orders o JOIN customers c ON c.id = o.customer_id LEFT JOIN items i ON i.order_id = o.id WHERE c.active = 1 AND ( o.placed_at >= '2026-01-01' OR o.status = 'open' ) GROUP BY o.id, c.name
Each clause starts a line, each selected column and condition sits under it, and AND starts its line, so a condition can be commented out on its own.
A common table expression in PostgreSQL
- Input
- with recent as (select customer_id, count(*) as n from orders where placed_at > now() - interval '30 days' group by customer_id) select c.name, r.n from recent r join customers c using (customer_id) order by r.n desc limit 10
- Dialect
- PostgreSQL
- Keyword case
- lower
- Indent
- 4 spaces
- Pretty
with recent as ( select customer_id, count(*) as n from orders where placed_at > now() - interval '30 days' group by customer_id ) select c.name, r.n from recent r join customers c using (customer_id) order by r.n desc limit 10
The query inside with recent as ( … ) is indented as a block of its own.
A SQL Server script with GO
- Input, SQL Server (T-SQL)
use Shop go select top 5 [Order ID], [Total] from dbo.Orders where [Total] > @min order by [Total] desc go
- Pretty
USE Shop go SELECT TOP 5 [Order ID], [Total] FROM dbo.Orders WHERE [Total] > @min ORDER BY [Total] DESC go
Each batch is formatted on its own and the go lines stay as written. The bracketed names keep their spaces.
A MySQL procedure with DELIMITER
- Input, MySQL
DELIMITER // create procedure touch(in id int) begin update items set seen = now() where item_id = id; end // DELIMITER ;
- Pretty
DELIMITER // CREATE PROCEDURE touch (IN id INT) begin UPDATE items SET seen = NOW() WHERE item_id = id; END// DELIMITER ;
The DELIMITER lines stay, and the procedure ends at //, so the MySQL client still runs the script. The body is laid out statement by statement, not indented inside BEGIN … END.
Frequently asked questions
BEGIN … END blocks, IF and loops are not indented by depth, and their keywords may keep their case. A note says so when the input creates a procedure. For MySQL, DELIMITER lines are kept, so the script still runs; see the last example.See also
- JSON Formatter & Minifier — to format JSON a query returns or stores.
- Text Compare & Diff Checker — to see what changed between two versions of a query.