SQL スタイルガイド:読みやすいクエリの整形ベストプラクティス
SQL スタイルガイドとは、クエリを読みやすくし、チームの diff を一貫させるための一連の取り決めだ。SQL 自体は気にしない。キーワードは大文字小文字を区別せず、空白も無視されるので、SELECT、select、SeLeCt はどれも同じように動くし、200 文字の一行クエリも、それを 20 行のインデント付きに展開したクエリも、まったく同じ行を返す。つまりスタイルとは、後からそのクエリを読む人間のためだけに存在する。
今すぐきれいなクエリが欲しいだけなら、SQL フォーマッターに貼り付け、方言を選び、結果をコピーすればいい。だが、その出力の背後にあるルールを理解しておくことこそが、プルリクエストのたびに議論する代わりにチーム標準を定められる鍵になる。本ガイドでは、本当に重要な選択を順に見ていく。キーワードの大文字小文字、インデントと改行、命名、方言固有のクセ、そしてそれらすべてを自動化する方法だ。
詳細に入る前に、ひとつ枠組みを示しておきたい。SQL は空白も大文字小文字も無視するので、これらのルールはどれもデータベースによって強制されるものではない。あくまで、クエリを読み、レビューし、保守する人間のために存在する。ここから二つの帰結が出てくる。第一に、唯一の「正解」が存在することはまれだ。これらの判断のほとんどは妥当な取り決めを一つ選び、それを全体に適用するという話であり、本ガイドは、どれか一つのスタイルが完全に勝つと装うのではなく、本物のトレードオフがどこにあるのかを正直に示す。第二に、ルールは要件ではなく取り決めなので、一貫して適用されたときにだけ価値が生まれる。だからこそ、どの節も同じ結論に行き着く。一度決めて、あとはツールに強制させる、というものだ。
なぜ SQL の整形が重要なのか
整形を支持する最も明快な論拠は、コードレビューに現れる。ORM やビルドステップは、クエリを区切りのない一行として吐き出すことが多い。
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=true group by u.id,u.name order by orders desc
これは誰もレビューできない。整形し直せば構造は一目瞭然で、diff も一行ずつレビューできる。
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 = true
GROUP BY u.id, u.name
ORDER BY orders DESC;
デバッグも同じように恩恵を受ける。スロークエリログから一行のクエリをコピーしてきて、それに三つの JOIN と入り組んだ WHERE があるとき、まず整形してしまえば「バグはどこだ」という問いが 30 秒のスキャンに変わる。問題のある述語は独立した行に並び、JOIN は積み重なって、うっかり生まれたデカルト積や忘れられたフィルターが、テキストの壁に埋もれる代わりに突然見えるようになる。同じ手は、別のシステムが生成した SQL を読むときにも効く。クエリビルダーやレポーティングツールは、正しいが読めない出力を吐くことで知られている。
一貫性は、より静かな勝利であり、時間とともに最も価値の高いものになる。全員が同じように整形すれば、diff には実際に変わったもの(新しいカラム、調整されたフィルター)だけが現れ、誰かの空白の好みが別の誰かの好みとぶつかって生じるノイズは消える。レビュアーの注意力は有限だ。それを再整形された空白に費やすのは浪費でしかない。一貫した整形はオンボーディングも楽にする。新しく入った人は、どれも同じ形に見えるクエリを読み、チームの形を一度学べば、それをどこにでも当てはめられる。これらのどれも、手作業での整形を必要としない。それが最終節のテーマでもある。ルールはあなたが決め、適用はツールが行う。
これらすべての土台には一つの不変条件があり、本ガイドを通じて繰り返されるので、はっきり述べておく価値がある。整形が変えるのは空白、改行、キーワードの大文字小文字、そしてコメントだけだ。クエリのロジックや結果を変えることは決してない。 整形されたクエリは同じクエリである。だからこそ、上の散らかったバージョンを安心して SQL フォーマッターに通しても、何が返ってくるか心配する必要はない。
キーワードの大文字小文字 — UPPERCASE か lowercase か
どんな SQL スタイルガイドでも最も古くからある論争は、予約キーワードを UPPERCASE にすべきか lowercase にすべきかだ。SQL はキーワードについて大文字小文字を区別しないので、どちらも有効だ。意見が分かれるのは可読性についてであり、選ぶ前に両方の言い分を理解しておく価値がある。
UPPERCASE キーワード支持の論拠
伝統的な論拠は視覚的なコントラストだ。SELECT、FROM、WHERE、JOIN、GROUP BY を大文字で書くと、キーワードが小文字のテーブル名やカラム名から浮き上がるので、エディタに色付けしてもらわなくても、クエリの形、つまりその句や構造をスキャンできる。
これは聞こえる以上に重要だ。なぜなら、SQL はシンタックスハイライトのない場所をいくらでも通っていくからだ。ログファイル、メールのやり取り、プルリクエストの説明、プレーンテキストの diff、Slack のメッセージ、モニタリングダッシュボード、スタックトレース。そのいずれにおいても、大文字キーワードだけが構造を読めるものに保ってくれる。ハイライトを剥ぎ取れば、select id from users where active は小文字の単語のスープだが、SELECT id FROM users WHERE active はぱっと見でもクエリとして読める。これは古いスタイルガイドの大半、データベースのドキュメント、そしてほぼすべての SQL の教科書で見かける取り決めであり、エディタがどのみち色を付けてくれる場合でも、多くの開発者が大文字キーワードをより馴染み深く感じる理由でもある。
lowercase キーワード支持の論拠
現代的な反論は、シンタックスハイライトがコントラストの問題を解決した、というものだ。あらゆるエディタや IDE がキーワードを明確に色付けするので、大文字にするのは冗長であり、読み手によっては、すべて大文字は怒鳴っているように読める。それに、キーワードごとに shift に手を伸ばさずに済む分、わずかにタイプも速い。
lowercase スタイルは、アナリティクスエンジニアリングの世界で本物の勢いを持っている。dbt コミュニティや、広く引用されるいくつかのチームのスタイルガイドは、ハイライトが視覚的な重みを担い lowercase はクエリを読みやすく穏やかに保つ、という論理で lowercase キーワードをデフォルトにしている。彼らに有利な、より微妙な論点もある。lowercase キーワードは snake_case のテーブル名やカラム名と同じ視覚的レベルに並ぶので、クエリ全体が、怒鳴るキーワードと静かな識別子という二つのレジスターが注意を奪い合うのではなく、一貫した一つのテキストとして読める。それが利点なのか欠点なのかは、まさにチームの意見が分かれるたぐいのものであり、それが唯一きちんと成り立つ結論へとつながる。
結論 — 選択より一貫性が勝つ
ここが実際に重要な部分だ。どちらを選ぶかは、一つを選んでそれを強制することに比べれば、はるかに重要度が低い。半分のクエリが SELECT と怒鳴り、もう半分が select とささやくコードベースは最悪の結果だ。なぜなら、その不一致自体がノイズになるからだ。一つのクエリ内での大文字小文字の混在は、さらに悪い。
一貫性が勝つ理由は、美学ではなく機械的なものだ。不一致な大文字小文字は diff に嘘をつかせる。レビュアーには、実際には誰かがキーワードを整形し直しただけの行「変更」が見え、本当の変更はノイズに紛れる。同じキーワードが三通りの表記で現れると、grep や検索の信頼性も下がる。一つの強制されたスタイルは、たった一つの決定と引き換えに、その手間をすべて取り除く。だから、チームとして決め、書き留め、規律に頼るのではなくツールに強制させよう。SQL フォーマッターには UPPERCASE、lowercase、Preserve の三つの選択肢を持つ Keywords コントロールがあるので、歴史的なクエリの山全体をワンクリックで一つのスタイルに正規化できる。同じクエリを、両方の方法でレンダリングしたものがこれだ。
-- UPPERCASE
SELECT id, email FROM users WHERE active = true ORDER BY created_at DESC;
-- lowercase
select id, email from users where active = true order by created_at desc;
チームが好む方を選べばいい。要は、すべてのクエリがそれに揃っていることだ。
インデントと改行
大文字小文字はキーワードの見た目を決める。インデントと改行は、クエリのロジックがページ上にどう写し取られるかを決め、可読性のほとんどはここに宿る。
「river」スタイル vs ブロックスタイル
Simon Holywell のよく知られた sqlstyle.guide は「river」スタイルを広めた。キーワードを右揃えにし、空白の縦のチャネルがクエリの真ん中を流れ下るようにするものだ。
SELECT id,
email,
created_at
FROM users
WHERE active = true
ORDER BY created_at DESC;
魅力は、SELECT、FROM、WHERE がその右端で揃い、カラムリストが river の右側にきれいに収まる点だ。ただし欠点は実務的だ。揃え方は最も長いキーワードの長さに依存するので、LEFT JOIN を一つ加えるだけで全体を再インデントする羽目になりかねない。手作業での維持は苦痛だし、一つのキーワードの長さが変わると隣接行の空白がずれるので、ノイズの多い diff を生む。
ブロック(または左揃え)スタイルは、主要な句をそれぞれ独立した行で左マージンから始め、句の中身をインデントする。
SELECT
id,
email,
created_at
FROM users
WHERE active = true
ORDER BY created_at DESC;
これが主流のデフォルトであり、ほとんどのツールが生成するものだ。まさにそれが安定しているからこそで、句を追加しても上の行が再整形されることはなく、diff は小さく保たれ、レイアウトは自動整形に耐える。river スタイルは完成したクエリが単独でどう見えるかを最適化する。ブロックスタイルは、クエリが時間とともにどう変化し、バージョン管理でどうレビューされるかを最適化する。リポジトリに置かれて編集されるものなら、ブロックスタイルの方が安全な賭けであり、本ガイドの残りもそれを前提にする。
スペース何個か — 2 vs 4 vs タブ
インデントすると決めたら、どれだけ深くするかを決めなければならない。よくある三つの答えには、それぞれ理由がある。
- 2 スペース — 最も一般的なデフォルト。diff をコンパクトに保ち、ネストしたクエリが画面の右端へ行進していくのを防ぐ。
- 4 スペース — ネストの各レベルにより多くの視覚的な間隔を与え、深いサブクエリや多段の CTE を含むクエリで役立つ。
- タブ — 各開発者がファイルを変えずに自分の表示幅を選べる。
ここに普遍的に正しい答えはない。だからこそ SQL フォーマッターは、三つすべて(2 spaces、4 spaces、Tab)を備えた Indent コントロールを公開している。一つを選び、どこにでも適用しよう。
どこで改行するか
インデント幅は簡単な部分だ。影響の大きい判断は、どこに改行を入れるかだ。
SELECTのカラム — 些細でないものは一列一行にし、カラムの追加や削除が diff で正確に一行だけに触れるようにする。とても短いクエリは一行のままでよい。FROMとJOIN— 各 JOIN を独立した行で始め、ON条件はその後ろに続けるか、下にインデントする。これで JOIN のグラフが読みやすくなる。WHERE— 各AND/ORを独立した行に置き、ブール論理が上から下へ読めるようにする。AND/ORが混在する条件では、グループを括弧でくくってインデントし、優先順位を読み手に推測させるのではなく明示する。
これらはガイドラインであって、法律ではない。些細な SELECT id FROM users WHERE id = 1 に 5 行は要らないし、無理に 5 行へ押し込むのは可読性を助けるどころか損なう。判断の目安はおおむねこうだ。クエリにカラムが一つか二つより多い、テーブルが一つより多い、条件が一つより多いなら改行する。その閾値を下回れば一行の方が明快で、上回れば積極的に改行する。良いフォーマッターは妥当な閾値をあなたの代わりに組み込んでくれるが、出力が決して意外に見えないよう、その原則を理解しておく価値はある。
先ほどの散らかった一行に適用すると、これらのルールはあらゆる句とあらゆる JOIN がひと目で見えるレイアウトを生む。
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 = true
GROUP BY u.id, u.name
ORDER BY orders DESC;
先頭カンマ vs 末尾カンマ
より小さいが根強い問い。複数行のカラムリストで、カンマはどこに置くのか。
-- Leading commas
SELECT
id
, email
, created_at
FROM users;
-- Trailing commas
SELECT
id,
email,
created_at
FROM users;
先頭カンマには本物の利点がある。カラムを追加・削除しても変わるのは一行だけだし、カンマの抜けは、問題の行が目立つので見つけやすい。末尾カンマはより自然に読め、実務でははるかに一般的だ。どちらも問題ない。一つを選び、フォーマッターに適用させて、二度と誰も考えなくて済むようにしよう。
テーブルとカラムの命名規則
整形は空白を司り、命名は識別子そのものを司る。そして、命名なしのスタイルガイドは不完全だ。
SQL 識別子の事実上の標準は snake_case だ。すべて小文字で、単語をアンダースコアで区切る。user_id、created_at、order_items のように。これがその地位を得たのは、単なる習慣ではなく具体的な理由による。snake_case の識別子は引用符を一切必要とせず、方言をまたいで一貫して振る舞う。一方 camelCase(アプリケーションコードで一般的)は、データベースが大文字小文字を畳む方法と衝突する。これについては後で触れる。
なぜこれがアプリケーションコードと異なるのかを、はっきりさせておく価値がある。ほとんどのプログラミング言語では、周囲のコードが識別子を支配し、camelCase や PascalCase が標準だ。対照的に SQL の識別子は、データベース自身の大文字小文字の畳み込みルールによって解釈され、そのルールこそが大文字小文字混在の名前を脆くする当のものなのだ。snake_case はこの問題全体を回避する。畳むべき大文字小文字がなく、引用符を付ける理由もなく、エンジンごとに振る舞いが変わるものもない。
ほぼすべての SQL スタイルガイドに登場する、いくつかの取り決めをさらに挙げる。
- テーブル名の単数 vs 複数は本物の対立だ。
users(複数、「このテーブルはユーザーを保持する」)とuser(単数、「各行が一人のユーザー」)の双方に支持者がいる。大文字小文字と同じく、選択そのものより、すべてのテーブルに一貫して適用することの方が重要だ。 - 予約語を識別子に使うのを避ける。 カラムに
order、user、tableと名付けると、どこでも引用符を付ける羽目になり、紛らわしいエラーを招く。代わりにorder_idやaccountを使おう。 - キーの命名を一貫させる。 主キーを
idとし、外部キーを<referenced_table>_id(たとえばuser_id)とすれば、JOIN が予測可能で自己説明的になる。
明示的に指摘しておく価値のある落とし穴が一つある。データベースのカラムをアプリケーションの変数のように名付けるチームを噛むからだ。PostgreSQL では、引用符なしの識別子は小文字に畳まれるので、SELECT userId FROM t は実際には userid という名前のカラムを探す。引用符を付けた瞬間、つまり "userId" と書けば、データベースは大文字小文字を保持し、"userId" と userid を二つの異なるカラムとして扱う。
-- Creates a column whose real name is lowercase "userid"
CREATE TABLE t (userId integer);
-- Both of these work — the name was folded to lowercase
SELECT userId FROM t;
SELECT userid FROM t;
-- This fails: "column \"userId\" does not exist"
-- The quotes force an exact, case-sensitive match
SELECT "userId" FROM t;
注意したいのは、データベースによって大文字小文字を畳む方向が違うことだ。Oracle は引用符なしの識別子を大文字に畳み、他のいくつかは小文字に畳む。そのため大文字小文字混在の引用符付き識別子は移植性すらない。きれいな抜け道は、引用符付き・大文字小文字混在の識別子を完全に避け、snake_case を貫くことだ。これで問題全体を回避でき、スキーマがどの方言でも読みやすく保たれる。
camelCase、snake_case、kebab-case のより深い比較、コードとデータをまたいでそれぞれがいつ正しい選択になるかについては、命名規則ガイドを参照してほしい。
SQL 方言をまたいだ整形
ここまでの内容は、おおむね方言に依存しない。大文字小文字、インデント、改行、命名は、どのデータベースを対象にしても当てはまる。だが「この SQL を整形して」は、クエリがあるデータベース固有の構文を使った瞬間、壁にぶつかる。その構文を認識しない汎用パーサーは、それを台無しにするからだ。トークンを誤った位置で分割したり、演算子を読み違えたり、引用文字を文字列の区切りと見なしてクエリの半分を飲み込んだりしかねない。ここで方言を意識した整形がその真価を発揮する。そしてそれが、フォーマッターが推測する代わりに、まずデータベースを選ばせる理由だ。以下に挙げる違いは、日常のクエリで最もよく出くわすものだ。
| 操作 | PostgreSQL | MySQL / MariaDB | SQL Server (T-SQL) | Oracle | Standard SQL |
|---|---|---|---|---|---|
| 文字列連結 | || または CONCAT() | CONCAT() | + または CONCAT() | || または CONCAT() | || |
| NULL のフォールバック | COALESCE() | COALESCE() / IFNULL() | COALESCE() / ISNULL() | COALESCE() / NVL() | COALESCE() |
| 行数の制限 | LIMIT | LIMIT | TOP / OFFSET … FETCH | FETCH FIRST | FETCH FIRST |
| 識別子の引用 | 二重引用符("…") | バッククォート | 角括弧([…]) | 二重引用符("…") | 二重引用符("…") |
文字列連結と NULL の扱い
最も一般的な日常操作のうち二つが、方言ごとに違う綴りで書かれる。
文字列連結:
-- PostgreSQL, Oracle, SQLite (standard operator)
SELECT first_name || ' ' || last_name AS full_name FROM users;
-- SQL Server (T-SQL uses +)
SELECT first_name + ' ' + last_name AS full_name FROM users;
-- Portable across dialects
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
NULL のフォールバック:
-- Standard SQL (works everywhere)
SELECT COALESCE(nickname, name) AS display_name FROM users;
-- SQL Server only
SELECT ISNULL(nickname, name) AS display_name FROM users;
-- MySQL / MariaDB only
SELECT IFNULL(nickname, name) AS display_name FROM users;
誤った方言に設定されたフォーマッターは、ISNULL や || 演算子を理解できず、周囲のクエリを誤ってパースしかねない。
行数の制限と識別子の引用
結果の行数を制限する構文は、最も方言が分かれる部分の一つだ。
-- PostgreSQL, MySQL, SQLite
SELECT id, name FROM users ORDER BY created_at DESC LIMIT 10;
-- SQL Server (T-SQL)
SELECT TOP 10 id, name FROM users ORDER BY created_at DESC;
-- Standard SQL / Oracle
SELECT id, name FROM users ORDER BY created_at DESC FETCH FIRST 10 ROWS ONLY;
識別子の引用も三通りに分かれる。識別子を引用しなければならないとき、たいていは予約語を使うか大文字小文字を保持するためだが、その区切り文字はデータベースによって異なる。
-- MySQL / MariaDB use backticks
SELECT `order`, `user` FROM `select`;
-- SQL Server (T-SQL) uses square brackets
SELECT [order], [user] FROM [select];
-- Standard SQL (PostgreSQL, Oracle, SQLite) uses double quotes
SELECT "order", "user" FROM "select";
MySQL のバッククォートを文字列の区切りだと思い込むフォーマッターや、T-SQL の角括弧を別の何かだと思うフォーマッターは、壊れた出力を生む。どれがどれかを伝えるのが方言設定だ。これは、クエリをデータベース間でコピー&ペーストするのがめったにきれいな差し替えにならない理由でもある。同じ論理的な意図、たとえば二つの文字列を連結する、NULL にフォールバックする、10 行に制限する、予約語を引用するといった意図が、方言をまたいで四通りに書かれており、あなたのデータベースを知っているパーサーだけが、それを破壊せずに再整形できる。
なぜ方言を意識した整形が重要なのか
まさにこれが、SQL フォーマッターが単一の汎用モードではなく、PostgreSQL、MySQL、SQL Server (T-SQL)、BigQuery、Snowflake、Oracle、SQLite、MariaDB、そして Standard SQL という九つの方言を備えて出荷される理由だ。正しいものを選ぶことは、推測して取り違える代わりに、パーサーが PostgreSQL のドル引用文字列と :: キャスト、T-SQL の角括弧識別子と TOP、BigQuery や Snowflake のウェアハウス固有関数、そして上記の引用ルールを正しく扱うことを意味する。整形する前にドロップダウンから実際のデータベースを選べば、出力は正しく、かつ慣用的に返ってくる。
SQL 整形の自動化
ルールを読むのは一つのことだが、それを手作業で適用すべき人は誰もいない。スタイルガイドの肝心な点は、機械がそれを強制することにある。どれだけ摩擦を取り除きたいかに応じて、整形を組み込める場所は三つある。
エディタで(保存時整形)
最も手間のかからない選択肢は、保存のたびに自動で整形することだ。VS Code には保存時に走る SQL フォーマッター拡張があり、JetBrains DataGrip や他の IDE のデータベースツールには、キーストロークや保存フックに割り当てられる組み込みフォーマッターが付いてくる。一度設定すれば、あなたのクエリは単純に未整形であることがなくなる。JavaScript の Prettier や Go の gofmt と同じモデルだ。難点は、エディタ設定が各開発者のマシン上に存在することで、保存時整形はあなたの SQL をきれいに保つが、それ単独でチームの残りの SQL まで保証するわけではない。それには次の層が必要だ。
CI でリンターと共に
チーム全体でスタイルを強制するには、チェックを継続的インテグレーションへ移そう。sqlfluff のような SQL リンターは、リントと自動修正の両方を行う。方言、キーワードの大文字小文字、インデント、カンマの位置といったルールを .sqlfluff の設定ファイルに記述し、sqlfluff lint を実行して違反を指摘し、sqlfluff fix でそれを修復し、合意されたスタイルから外れたプルリクエストを CI に落とさせる。これはフロントエンドのリポジトリをゲートする ESLint や Prettier と同じ発想だ。スタイルは、誰かが残し忘れないようにしなければならないレビューコメントであることをやめ、機械が決して忘れない成否のチェックになる。その見返りとして、スタイルの議論はプルリクエストのたびにではなく、設定を書くときに一度だけ起こる。
一回限りのオンライン整形
ときには、醜いクエリが一つだけあって、何かをインストールする気はまるでない、ということもある。ログからのスニペット、同僚の Slack メッセージ、ドキュメントに貼り付けようとしているクエリだ。そういうときは、SQL フォーマッターに貼り付け、方言、大文字小文字、インデントを選び、きれいな結果をコピーしよう。
ここではプライバシーの詳細が重要で、見落とされやすい。多くのオンラインフォーマッターは、処理のために貼り付けたテキストをサーバーへ送る。つまりクエリのコピー、テーブル名やカラム名、ときには本番障害からのリテラル値が、あなたのマシンを離れる。SQL フォーマッターは完全にブラウザ内で動くので、あなたの SQL がどこかにアップロードされることは決してない。これにより、本番スキーマや独自のロジックに触れるクエリを整形しても安全になる。まさに、きれいな整形を最も望み、クエリを第三者に渡すことを最も望まない状況だ。同じワークフローで他のフォーマットも扱っているなら、兄弟ツールの JSON 整形ツールも同じように動く。同じブラウザ内処理で、同じワンクリックコピーだ。
三つのアプローチは互いに排他的ではなく、最良の構成はたいていそれらを組み合わせる。書いている間の速い内側のループには保存時整形、チーム標準を強制する最後の砦には CI リンター、そしてリポジトリに触れることのない使い捨てのスニペットにはオンラインフォーマッター。どれに手を伸ばすにせよ、最後にもう一度この不変条件を思い出そう。これらのツールはどれも、クエリの動作を変えない。空白、改行、大文字小文字、コメントを並べ替えるだけで、それ以外は何も変えない。
よくある質問
SQL のキーワードは大文字と小文字のどちらにすべきか?
どちらも有効だ。SQL のキーワードは大文字小文字を区別しないからだ。UPPERCASE はログや diff など、シンタックスハイライトのない環境でキーワードを目立たせる。lowercase はタイプが楽で、すでにキーワードを色付けする現代のエディタに馴染む。本当に重要なのは、チーム全体が一つを選び、フォーマッターがそれを強制することだ。大文字小文字の混在こそ最悪の選択だ。
SQL に最適なインデントは?
2 スペースは最も一般的なデフォルトで、diff をコンパクトに保つ。4 スペースは深くネストしたクエリを読みやすくする。タブは各開発者が自分の表示幅を選べるようにする。唯一の正解はない。一つを選び、チーム全体で一貫して適用しよう。このツールを含め、ほとんどの SQL フォーマッターは三つの選択肢すべてをサポートしている。
SQL を自動で整形するには?
SQL を自動で整形する方法は三つある。エディタでの保存時整形(VS Code や DataGrip)、CI 内でスタイルを自動修正する sqlfluff のようなリンター、そして一回限りの貼り付けに使うオンライン SQL フォーマッターだ。オンラインの手段はインストールが要らないので最も速い。貼り付けて、方言を選び、結果をコピーするだけだ。
SQL で先頭カンマと末尾カンマのどちらを使うべきか?
先頭カンマ(各行の先頭にカンマ)はカラムを追加・削除するときの diff をきれいにし、カンマの抜けを見つけやすくする。末尾カンマ(行末のカンマ)はより自然に読め、より一般的だ。どちらも、どの SQL スタイルガイドでも許容される。肝心なのは一つを選び、フォーマッターに自動で適用させることだ。
SQL を整形するとクエリの動作は変わるのか?
変わらない。SQL の整形が変えるのは空白、改行、キーワードの大文字小文字、そしてコメントだけだ。クエリのロジックを変えることは決してない。整形されたクエリは元と完全に同じ結果を返すので、レビューや実行の前に本番クエリを美化することすら、まったく安全だ。
SQL のテーブルとカラムにはどの命名規則を使うべきか?
snake_case、つまりすべて小文字でアンダースコア区切りの表記が、SQL のテーブル名とカラム名の事実上の標準だ。引用符を避けられ、方言をまたいで安全だからだ。主キー(id)と外部キー(user_id)の命名を一貫させ、引用符の頭痛を防ぐために order や user のような予約語を識別子に使うのは避けよう。
PostgreSQL や T-SQL のような特定の方言向けに SQL を整形するには?
まずフォーマッターで一致する方言を選ぼう。PostgreSQL モードは :: キャストとドル引用文字列を正しく扱う。SQL Server (T-SQL) モードは角括弧の [identifiers] と TOP を理解する。誤った方言を選ぶと、汎用パーサーが方言固有の構文を台無しにするので、整形する前に必ず実際のデータベースに設定しよう。
標準的な SQL スタイルガイドはあるのか?
公式の標準はないが、広く参照されるものはいくつかある。Simon Holywell の sqlstyle.guide や、Mozilla や dbt コミュニティのようなチームの公開スタイルガイドだ。それらに共通する合意、すなわち一貫したインデント、snake_case の識別子、各主要句の前での改行こそが本ガイドが体系化するものであり、フォーマッターがあなたの代わりにそれを強制できる。