メインコンテンツへスキップ

← ブログ一覧へ

なぜ SQL を整形するのか(そしてフォーマッターは何をするのか)

ORM がクエリをログに出すと、300 文字の一行としてコンソールに現れます。フォーマッターはその文字の壁を、各句が定位置に収まった、見渡せるインデント付きのクエリに変えます。同じクエリで——ただ読めるようになるだけです。実際に何が起きているのか見ていきましょう。

整形が変えるもの(と変えないもの)

整形が触れるのは空白・改行・インデントだけ——それに任意でキーワードの大小です。SELECTFROMWHEREJOINGROUP BY をそれぞれの行に置き、列や条件をインデントし、入れ子構造がひと目でわかるように整えます。

決して変えないのは、テーブル・列・値・ロジックです。整形後のクエリは、詰まっていたときとまったく同じ結果を返します。つまり整形は検証ではありません——列名の綴りミスや、実際に動くかどうかは教えてくれません。

方言:ツールがどのデータベースかを尋ねる理由

SQL には標準がありますが、各データベースが独自の味付けを足すため、フォーマッターは正しく解析するのにどれかを知る必要があります:

  • 識別子の引用符——MySQL はバッククォート(`col`)、PostgreSQL と標準 SQL は二重引用符("col")。
  • 行数の制限——MySQL/SQLite/PostgreSQL は LIMIT、SQL Server は TOP
  • 型変換——PostgreSQL の value::int は他に対応する書き方がありません。

方言を間違えるとこれらが誤解析され、インデントが崩れます。貼り付ける前に SQL フォーマッターで実際に使うデータベースを選びましょう。

大文字のキーワード:規則ではなくスタイル

多くのチームはキーワードを大文字(SELECTFROM)で書き、テーブル名や列名と区別します。SQL 自体はキーワードの大小を区別しないので、これは純粋に可読性の慣習です——フォーマッターならクエリ全体をワンクリックで統一できます。

なぜローカルで行うのか

クライアント側のフォーマッターは、ブラウザ内で SQL を解析して出力し直します。スキーマやビジネスロジックをしばしば映し出すクエリが、あなたのマシンから出ることはありません。

関連ツール

整形の前後

同じクエリを、ORM が 1 行に潰したものと、整形したもの:

select u.id,u.name,count(o.id) as orders from users u left join orders o on o.user_id=u.id where u.active=1 group by u.id,u.name having count(o.id)>0 order by orders desc;

整形すると、構造が上から下へ読み取れます:

SELECT
    u.id,
    u.name,
    COUNT(o.id) AS orders
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.active = 1
GROUP BY u.id, u.name
HAVING COUNT(o.id) > 0
ORDER BY orders DESC;

結果は同じですが、JOIN・絞り込み・グループ化がひと目で分かります。

カンマは行末か行頭か

列の書き方には主に 2 通りあります。行末カンマ(各行末尾の u.id,)か、行頭カンマ(各行先頭の , u.name)。行頭カンマはバージョン管理の差分をきれいに保ちます——列の追加が 2 行ではなく 1 行で済むからです——が、どちらも正しく、多くのフォーマッターで選べます。どちらを選ぶかより、コードベース内で統一されていることが大切です。

よくある疑問

  • 整形は性能に影響する? しません。パーサーは無意味な空白とキーワードの大小を無視するので、整形後のクエリはエンジンにとって等価です。空白が意味を持つのは文字列リテラルの中身だけです。
  • 整形した SQL はコミットすべき? ビュー・マイグレーション・ストアドプロシージャなら、はい——統一された体裁は差分を小さく保ち、レビューを速くします。
  • ただし整形は壊れたクエリを直しません。 テキストを並べ替えるだけです。誤りを見つけるには実際のデータベースや linter を使いましょう。あとで結果を書き出す?JSON を CSV・Excel に変換する方法をどうぞ。