MariaDB SQL Formatter

Select MariaDB as the dialect, paste your query and press Ctrl/Cmd+Enter. The lexical rules match MySQL, while MariaDB-only clauses like RETURNING get their own lines.

Input

Settings

History

Load from URL

Why MariaDB has its own setting

MariaDB began as a MySQL fork and still reads text the same way: identifiers in backticks, strings in single or double quotes, backslash escapes such as 'can\'t', and # line comments. Where the two differ is grammar. MariaDB has had DELETE … RETURNING since 10.0 and INSERT … RETURNING since 10.5, and the MariaDB setting treats RETURNING as a clause. With the MySQL setting the same statement still formats, but returning cart_id, sku is glued onto the end of the WHERE condition and left in lower case.

So choose by server, not by habit. A query written for MariaDB 10.6 or 11.x belongs under MariaDB; one that must also run on MySQL 8 is better checked under MySQL, since that is the stricter target for RETURNING and sequences.

Sequences, temporal tables and JSON

NEXTVAL(invoice_seq), LASTVAL(invoice_seq) and NEXT VALUE FOR invoice_seq format as ordinary expressions inside SELECT and INSERT lists. CREATE SEQUENCE itself is laid out less neatly: START WITH 1000 is split so that WITH begins a new line, as if a CTE followed. The statement is unchanged apart from whitespace, so it still runs.

For system-versioned tables, FOR SYSTEM_TIME AS OF TIMESTAMP '2026-03-01 00:00:00', BETWEEN … AND … and ALL stay on the same line as the table name, which keeps a point-in-time query easy to scan. WITH SYSTEM VERSIONING at the end of a CREATE TABLE lands on a WITH line of its own. Application-time periods are less lucky: in FOR PORTION OF valid_period FROM … TO …, the FROM is mistaken for a new FROM clause.

JSON_TABLE(items, '$[*]' COLUMNS (…)) is expanded with one column definition per line, and INTERSECT and EXCEPT separate their two queries cleanly.

Upserts, procedures and executable comments

MariaDB has no AS new row alias for ON DUPLICATE KEY UPDATE, so upserts refer to the incoming row with VALUES(col) or its synonym VALUE(col). Prefer VALUE(qty) when formatting: the plural form is read as the start of a VALUES clause and gets broken across lines, while the singular stays inline.

Stored routines format best without DELIMITER. With DELIMITER $$, the closing END $$ and the next DELIMITER ; end up on one line, so remove those client commands first. The body statements between BEGIN and END are each laid out, though not indented under BEGIN.

One caveat for Minify: the generic /*! … */ executable comment is preserved, but MariaDB’s own /*M!100500 … */ form is treated as an ordinary comment and removed. Keep such statements in formatted form, or check the minified output before using it.

Useful options

Commas → Leading suits long INSERT column lists and multi-row VALUES. Function case → UPPER makes JSON_VALUE and DATE_FORMAT stand out from column names. To look for unclosed quotes or brackets without changing the layout, open the SQL validator; to squeeze a query onto one line, the SQL minifier does only that.

Examples

Bulk customer insert returning new IDs

INSERT … RETURNING laid out as its own clause, with leading commas in the value rows and the returned columns.

Input
insert into customers (email, country, signup_source) values ('ana@example.com', 'PT', 'web'), ('li@example.com', 'SG', 'app') returning id, email, created_at;
Output
INSERT INTO
  customers (email, country, signup_source)
VALUES
  ('ana@example.com', 'PT', 'web')
, ('li@example.com', 'SG', 'app')
RETURNING
  id
, email
, created_at;
Open this example in the tool

Price history at a point in time

A system-versioned table queried with FOR SYSTEM_TIME AS OF, which stays on the FROM line.

Input
select p.sku, p.amount, p.row_start from prices for system_time as of timestamp '2026-03-01 00:00:00' as p where p.sku like 'SKU-1%' order by p.sku;
Output
SELECT
  p.sku,
  p.amount,
  p.row_start
FROM
  prices FOR system_time AS of TIMESTAMP '2026-03-01 00:00:00' AS p
WHERE
  p.sku LIKE 'SKU-1%'
ORDER BY
  p.sku;
Open this example in the tool

Order lines from a JSON column

JSON_TABLE with a COLUMNS list, expanded one column definition per line.

Input
select o.id as order_id, jt.sku, jt.qty from orders o, json_table(o.items, '$[*]' columns (sku varchar(32) path '$.sku', qty int path '$.qty')) as jt where o.created_at >= '2026-01-01' and jt.qty > 1;
Output
SELECT
  o.id AS order_id,
  jt.sku,
  jt.qty
FROM
  orders o,
  json_table (
    o.items,
    '$[*]' columns (
      sku VARCHAR(32) path '$.sku',
      qty INT path '$.qty'
    )
  ) AS jt
WHERE
  o.created_at >= '2026-01-01'
  AND jt.qty > 1;
Open this example in the tool

Stock upsert using VALUE()

A # comment and an ON DUPLICATE KEY UPDATE that refers to the incoming row with VALUE(qty).

Input
# nightly stock sync
insert into inventory (sku, warehouse_id, qty) values ('SKU-1001', 3, 40), ('SKU-1002', 3, 12) on duplicate key update qty = qty + value(qty), updated_at = now();
Output
# nightly stock sync
INSERT INTO
  inventory (sku, warehouse_id, qty)
VALUES
  ('SKU-1001', 3, 40),
  ('SKU-1002', 3, 12)
ON DUPLICATE KEY UPDATE
  qty = qty + value (qty),
  updated_at = now();
Open this example in the tool

Common errors and how to fix them

ErrorCauseFix
This string is never closed — the ' has no matching '
Explained
A string ends in a backslash, as in 'D:\exports', so the final quote is escaped instead of closing the string.Escape the trailing backslash as \, or build the path with CONCAT so no literal ends in a backslash.
"::int" is not valid MariaDB syntaxA Postgres cast shorthand was carried over into a MariaDB query.Use CAST(qty AS INT) or CONVERT(qty, SIGNED) instead of the :: operator.
"[Order" is not valid MariaDB syntaxBracket-quoted names from SQL Server were pasted in; MariaDB quotes names with backticks.Replace the brackets with backticks, or select the T-SQL (SQL Server) dialect if the query is meant for SQL Server.
This '(' is never closed
Explained
A JSON_TABLE COLUMNS list or nested function call is one closing parenthesis short.Close the innermost open bracket first, working outwards from the position shown.

Frequently asked questions

Is MariaDB SQL formatted differently from MySQL?

Strings, quotes and comments are read identically. The difference is in MariaDB-only grammar such as RETURNING, which only the MariaDB setting lays out as a clause.

Can I format queries on system-versioned tables?

Yes. FOR SYSTEM_TIME AS OF, BETWEEN and ALL are kept beside the table name, and WITH SYSTEM VERSIONING is accepted in CREATE TABLE.

Does it work with HeidiSQL or DBeaver exports?

Yes, as long as you paste plain SQL. Remove DELIMITER lines from routine exports before formatting, then add them back.

Will minifying keep my /*M! */ version comments?

No. Minify keeps /*! / and /+ */ comments but strips /*M! */ ones, so use formatted output for scripts that rely on them.

Where does my SQL go when I format it?

Nowhere. The MariaDB rules and the formatter are bundled into the page and run locally in your browser.

Related tools