Skip to content
CornerTools

SQL Formatter

Format and beautify SQL for MySQL, PostgreSQL, SQL Server, Oracle and more.

1
1
Characters: 0
Format
Indent
Keyword case
AND / OR position

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

Partly. Each statement inside a procedure is formatted, but 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.
Databases do not mind: keywords are case-insensitive in all of them. Upper case is the older convention and sets keywords apart from names in plain text, which is why it is the default. Many teams now write lower case, since editors colour keywords anyway. Choose Preserve to keep the case as written. Table and column names are never changed, because some databases compare quoted names by case.
No. It checks that the SQL can be read in the chosen dialect, well enough to lay it out. It does not know your tables, so a misspelt column or a wrong type formats without complaint. Minified does not parse the SQL at all.

See also