SQLフォーマッター

SQLクエリを整形、または1行に圧縮

SQLフォーマッターについて

このフォーマッターはSQLの構文を解析するパーサーではなく、文字列をトークン(キーワード・識別子・数値・文字列・コメント・記号)に分けて規則で改行する軽量ツールです。SELECT、FROM、WHERE、JOIN、GROUP BYなどの句ごとに改行し、既知のキーワードを大文字にし、SELECTのカンマやWHEREのAND/ORごとに行を分けます。単一引用符の文字列とコメントの中身は変えません。

パーサーではないので、クエリが正しいかは判断せず、データベースごとの方言もすべては知りません。以下ではMySQL・PostgreSQL・SQL Server固有の構文のうち何をそのまま保つか、また整形では解決しない問題を説明します。

方言の構文の扱い

標準SQLでは単一引用符が文字列、二重引用符が識別子で、文字列中の引用符は'It''s'のように2つ重ねます。このツールはこの規則とMySQLのバッククォート識別子`id`、そして以下の方言の構文を1つのまとまりとして扱います。

  • MySQLのバックスラッシュエスケープ文字列('It\'s')は内容を変えずに残します。バックスラッシュとして読むと文字列が閉じない場合は、標準SQLの規則('')で読み直します。
  • MySQLの#コメントを認識します。圧縮すると#コメントは消えるので、次の行がコメントに飲み込まれることはありません。PostgreSQLの#>、#>>、#-は演算子として扱います。
  • PostgreSQLの->>、->、@>、<@、||、::は分割しません。::はcreated_at::dateのように前後に空白を入れません。$$ ... $$や$tag$ ... $tag$で囲んだ本体は文字列として扱い、変更しません。
  • 文字列に接している記号は元の間隔を保ちます。array['a']はそのまま残ります。
  • SQL Serverの角括弧識別子[order id]は空白を含めてそのまま残します。
  • 圧縮では--と/* */のコメントを消しますが、/*+ ... */のオプティマイザヒントとMySQLの/*! ... */実行コメントは残します。

整形では直らないこと

代表的なのはANDとORの優先順位です。ANDのほうが先に結合するため、a = 1 OR b = 2 AND c = 3はa = 1 OR (b = 2 AND c = 3)です。フォーマッターはANDとORを同じ深さに並べるので、3つの条件が対等に見えてしまいます。意図が(a = 1 OR b = 2) AND c = 3なら括弧を自分で書く必要があります。

LEFT JOINの右側テーブルの条件をWHEREに書いた場合も同じです。注文のないユーザーではo.created_atがNULLになり、条件が真にならないため行が消え、結果はINNER JOINと同じになります。残したいなら条件をONに移します。= NULLが常にUNKNOWNになりIS NULLが必要な点も、整形前後ともに「有効なSQL」のままです。

例

1行のクエリを整える

入力
select u.id, u.name, count(o.id) as cnt from users u left join orders o on o.user_id = u.id where u.active = 1 and o.created_at >= '2026-01-01' group by u.id, u.name having count(o.id) > 3 order by cnt desc limit 10;
結果
SELECT u.id, u.name, count(o.id) AS cnt FROM users u LEFT JOIN orders o ON o.user_id = u.id WHERE u.active = 1 AND o.created_at >= '2026-01-01' GROUP BY u.id, u.name HAVING count(o.id) > 3 ORDER BY cnt DESC LIMIT 10;

整形すると、WHEREのo.created_at条件がLEFT JOINを実質的に内部結合にしていることが見えてきます。countは関数名なので小文字のままです。

ANDとORが並んで見える

入力
select * from t where a = 1 or b = 2 and c = 3
結果
SELECT * FROM t WHERE a = 1 OR b = 2 AND c = 3

実際の意味はa = 1 OR (b = 2 AND c = 3)です。

PostgreSQLの演算子を保つ

入力
select id, data->>'name' as n, created_at::date from t where tags @> array['a']
結果
SELECT id, data ->>'name' AS n, created_at::date FROM t WHERE tags @> array['a']

->>、::、@>はそれぞれ1つのまとまりのまま残ります。文字列'name'に接している->>は元の間隔のままです。

圧縮時のヒントと#コメント

入力
SELECT /*+ INDEX(o idx_user) */ id FROM o # note WHERE a = 1
結果
SELECT /*+ INDEX(o idx_user) */ id FROM o WHERE a = 1

オプティマイザヒントは残り、# noteのコメントだけが消えます。次の行のWHERE句はそのまま保たれます。

使い方

  1. SQLを貼り付けます。複数の文は;で区切ります。
  2. インデント幅を選び、整形または圧縮を押します。
  3. 結果を元のSQLと比べてから使います。

よくある質問

構文エラーを見つけてくれますか?

いいえ。トークン単位で改行するだけなので、誤ったクエリもそのまま整形されます。

関数名が小文字のままです。

大文字にするのは組み込みのキーワード一覧にある語だけです。

圧縮したSQLをコードに入れてもいいですか?

使えますが、通常のコメントは消え、ヒント(/*+ */)とMySQLの実行コメント(/*! */)だけが残ります。必要なコメントがないか確認してください。

PostgreSQLの演算子に対応していますか?

->>、->、@>、<@、||、::と$$のドル引用符は分割せずに残します。方言の設定はないので、それ以外の固有構文は元のSQLと比べてください。

出典

基準日:

プライバシーとデータの扱い