SQL クエリをフォーマットする方法
整っていないSQLは、バグを生む最速の方法の1つです。クエリがインデントもなく1本の長い行になっていると、どの条件がどの結合に適用されるのか、サブクエリがどこで始まりどこで終わるのか、ロジックが正しいのかを把握するのが難しくなります。ブラウザベースのフォーマッターは、クエリをサーバーにアップロードせずに、整形作業全体をローカルで処理します。
整形が重要な理由
- デバッグ: よく整形されたクエリはロジックエラーを可視化します。推測なしでSELECTからWHERE、JOINへの流れを追えます。
- コードレビュー: レビュアーは整形されたSQLを数秒で読めます。1行のクエリはまずそれを頭の中でパースさせます。
- 保守: 数か月後にクエリに戻ったとき、整形されていれば一目で何をするものかわかります。
- コラボレーション: チーム全体で一貫した整形があれば、誰もが同じようにSQLを読みます。
- オンボーディング: 新しいチームメンバーは、すべてのクエリの口頭での歴史を必要とせずに、整形されたSQLを読めます。
- ドキュメント: SQLが設計ドキュメント、運用手順書、Wikiに現れるとき、整形されたクエリは開発者でない人にも追いやすいです。
- バージョン管理の差分: 整形されたSQLは、クエリ全体を整形し直さずに1つの句を変更したとき、よりクリーンな差分を生みます。
SQLを整形する手順
- SQLを貼り付ける: ミニファイされた、または乱雑なクエリをフォーマッタに入力します。SELECT、INSERT、UPDATE、DELETE、CREATE TABLE、サブクエリと結合を含む複雑なクエリを扱えます。
- オプションを設定: インデントサイズと、キーワードを大文字にするかを選びます。これらの設定はプロジェクトのスタイルガイドに合わせます。
- 結果をコピー: 整形されたSQLはエディタ、データベースクライアント、ドキュメントに貼り戻す準備ができています。
良い整形がもたらすもの
select u.name, o.total from users u join orders o on u.id = o.user_id where o.total > 100 and u.active = 1 order by o.total descのようなクエリは、次のようになります:
SELECT
u.name,
o.total
FROM users u
JOIN orders o
ON u.id = o.user_id
WHERE o.total > 100
AND u.active = 1
ORDER BY o.total DESC
各句は独立した行から始まります。条件は親の句の下にインデントされます。結合とそのON条件は明確にペアになっています。
SQL整形の慣習、簡単な歴史
SQLは1974年にIBMの研究者Donald ChamberlinとRaymond Boyceによって作られ、当初SEQUEL(Structured English Query Language)と呼ばれていました。元の名前の「QL」は、言語が英語のように読めるようにする意図を反映していました。最初から、この人間が読める設計は1つの慣習を暗示していました。文章のように上から下に読めるよう、句をインデントすることです。
1980年代と1990年代のほとんど、SQLはテキストエディタで手書きされ、整形は個人的なものでした。一部のショップは「リバースタイル」(すべてのキーワードが仮想列の右側で縦方向に揃う)を採用し、他は「エジプトスタイル」(中括弧を同じ行に置くスタイル)を使い、ほとんどは著者が好む形式を使いました。
最初に広く使われたSQLフォーマッタはApex SQL Formatter(2000年)で、DevartのSQL Complete(2002年)とRed GateのSQL Prompt(2003年)が続きました。これらのツールは、SQL ServerとOracleの開発者にIDEレベルの整形をもたらしました。2010年までに、すべての主要なIDE(SSMS、DataGrip、DBeaver)に組み込みのSQL整形が備わり、オンラインフォーマッタが場当たり的なクリーンアップの標準になりました。
2017年にフォーマッタのエコシステムは、sql-formatter(npm)とともに移り変わりました。これは、現在ほとんどのブラウザベースのSQLフォーマッタを支えているオープンソースのJavaScriptライブラリで、本ツールにも含まれます。モダンなフォーマッタは方言の違い(MySQLのバックティック、PostgreSQLのウィンドウ関数、SQL Serverの角括弧)を扱い、一貫した設定可能な出力を生成します。
主要企業が使うSQLスタイルガイド
ほとんどのプロフェッショナルなコードベースは、公開された複数のSQLスタイルガイドのうちの1つに従います:
| スタイルガイド | 由来 | 主な慣習 |
|---|---|---|
| Mozilla SQL Style | Mozilla | 大文字キーワード、snake_caseの名前、2スペースインデント |
| GitLab SQL Style | GitLab Data Team | 大文字キーワード、小文字の名前、4スペースインデント、先頭カンマ |
| Holistics SQL Style | Holistics | 大文字キーワード、snake_case、2スペース、末尾カンマ |
| Simon Holywell SQL | 個人/人気 | 「リバー」アラインメント、大文字キーワード |
| dbt SQL Style | dbt Labs | 小文字キーワード(モダンな方言)、snake_case、先頭カンマ |
| PostgreSQL Wiki Style | PostgreSQLコミュニティ | 小文字キーワード、snake_case、K&Rスタイルのインデント |
新規プロジェクトを始める場合は、確立されたガイドの1つを選んでください。既存のコードベースに加わる場合は、すでにあるものに従ってください。プロジェクト内での一貫性は、特定のスタイルよりも重要です。
よくある整形の選択肢
- キーワードのケース: 大文字(最も一般的、キーワードが視覚的に際立つ)、小文字(モダンなdbt / Snowflakeスタイル)、または元のケース(一部のIDEは入力どおりを保持します)。
- 識別子のケース: snake_caseはPostgreSQLとほとんどのUnix向きのデータベースのデフォルト。PascalCaseまたはcamelCaseはOracleやSQL Serverの伝統。
- インデント: 2スペース(コンパクト、80文字ターミナルに収まる)、4スペース(ほとんどのコードスタイルガイドに合う)、またはタブ(SQLではまれ)。
- カンマの配置: 末尾カンマ(個別の行の各列の後)または先頭カンマ(次の行の先頭にカンマ、列の追加/削除が容易)。
- 行の長さ: 80文字(ターミナル向き)、120文字(モダンなIDEのデフォルト)、または無制限(本番ではあまり一般的でない)。
- JOINスタイル: ANSIのJOINキーワード(推奨)対、WHEREに結合条件を持つカンマ区切りFROMの古いスタイル(非推奨)。
- サブクエリの整形: 括弧内のサブクエリをインデント、明確さのために共通テーブル式(CTE)を使う、または明示的なエイリアスでネストする。
方言の違い
SQLフォーマッタは方言固有の構文を扱う必要があります:
| 方言 | 特徴 |
|---|---|
| PostgreSQL | ウィンドウ関数、LATERAL JOIN、ドルクォート文字列($$)、CTE中心のスタイル |
| MySQL / MariaDB | バックティック識別子、LIMIT句の構文、REPLACE INTO |
| SQL Server(T-SQL) | 角括弧識別子、TOP句、OUTPUT句、MERGE |
| Oracle(PL/SQL) | DUALテーブル、ROWNUM、階層的なCONNECT BY、ドットサフィックスのパッケージ呼び出し |
| SQLite | 限定的な型システム、REPLACE / UPSERT、単一ファイルデータベース |
| Snowflake | Variantデータ型、QUALIFY句、COPY INTO |
| BigQuery | バックティック識別子、ARRAY / STRUCT型、EXCEPT / REPLACE列リスト |
| Redshift | PostgreSQL由来だが特徴的なDDL、S3からのCOPY |
良いフォーマッタは方言ヒントを検出または受け入れ、他の方言が拒否する構文を扱います。
よくある落とし穴
- 本番スクリプト内での再整形: すでに部分的に適用されているマイグレーションスクリプトの空白を変更すると、マイグレーションツールがハッシュでフィンガープリントしている場合に問題を引き起こすことがあります。最初の実行前に整形してください。
- 文字列リテラルの再整形: クエリ内の複数行文字列はSQLフォーマッタによって再整形されてはいけません。一部の素朴なフォーマッタはインライン文字列を壊します。
- コメントの消失や誤配置: SQLコメント(単一行のダッシュと複数行のスラッシュアスタリスク)は整形後も残らなければなりません。一部のフォーマッタは混乱する方法でコメントを削除または移動します。
- 識別子のクォートが変わる: PostgreSQLの二重引用符付き識別子やMySQLのバックティック識別子は特定の意味を持ちます。クォートを取り除いて「正規化」するフォーマッタは、識別子がクォートを必要としていた場合(予約語、PostgreSQLでの大文字小文字の混在)、クエリの動作を変える可能性があります。
- ウィンドウ関数の誤った整形: OVER (PARTITION BY x ORDER BY y)は読みやすいままにすべきです。ウィンドウ関数の括弧内での積極的な行折り返しは、汚い出力を生みます。
- CTEチェーンの過剰なインデント: WITH cte1 AS (...), cte2 AS (...)は、一部のフォーマッタによって深くネストされすぎることがあります。ほとんどのモダンなフォーマッタはCTEを最上位レベルに保ちます。
- ドルクォート文字列(PostgreSQL関数): $$でラップされた関数本体はその内容を再整形してはいけません。一部のフォーマッタはそれらを壊します。
- ベンダー固有のキーワードの誤分類: QUALIFY(Snowflake)やLATERAL(PostgreSQL)を認識しないフォーマッタは、それらを正しく大文字化または整列しないかもしれません。
- 制御フローを持つストアドプロシージャ: T-SQLやPL/SQLのBEGIN/END、IF/THEN/ELSEブロックには、純粋なクエリとは異なるインデントルールが必要です。
使いこなしのヒント
- コミット前に整形する: SQLをバージョン管理に追加する前にフォーマッタに通します。これにより差分がクリーンになり、レビューはスタイルではなくロジックに集中できます。
- 一貫したキーワードのケースを使う: 大文字または小文字のキーワードを選び、プロジェクト全体で続けます。スタイルを混ぜるとクエリが読みにくくなります。
- 複雑なクエリを分解する: 整形後もクエリが読みにくい場合は、CTE(共通テーブル式)やビューに分解することを検討してください。整形は本質的に複雑なロジックを修正できません。
- 構文ハイライトを確認する: 良いフォーマッタは、キーワード、文字列、数値を視覚的に区別する色付きのハイライトを提供します。これはタイポの発見に役立ちます。
- 変更したものだけを整形する: 大きな既存のコードベースで一度にすべてを整形すると、実際の変更を覆い隠す巨大な差分が生まれます。クエリに触れるたびに段階的に整形しましょう。
- エディタを設定する: VS Code(SQLTools、vscode-sql-formatter)、DataGrip、DBeaver、pgAdminはすべて組み込みまたは拡張機能ベースのフォーマッタを持っています。一度設定すれば後は忘れて使えます。
- 大文字小文字を区別するデータベースに注意: PostgreSQLはクォートされた識別子で大文字小文字を区別します。クォートされた識別子のケースを変えるフォーマッタはクエリを壊します。
- 整形したクエリをテストする: 再整形後、クエリを実行して出力が変わっていないことを確認しましょう。ほとんどのフォーマッタは信頼できますが、フォーマッタのバグがクエリを破損する可能性があります。
- ネストされたサブクエリより CTEを使う: CTEチェーンは整形後でも、同等のネストされたサブクエリよりほぼ常に読みやすくデバッグしやすいです。
プライバシーと機密クエリ
SQLフォーマッタは完全にブラウザ内で動作します。貼り付けたクエリ、中間処理、整形された出力はすべてデバイス上に留まります。サーバーへのアップロード、ロギング、第三者との共有は一切ありません。
これはSQLクエリが極めて機密性の高い情報を含むことが多いからです。製品アーキテクチャを明かすテーブル名、ビジネスロジックとメトリクスを露呈する列名、WHERE句にある実際の顧客ID、ストアドプロシージャ内の内部APIエンドポイント、テストデータ内のSSN(社会保障番号)とクレジットカード番号、人事クエリの従業員報酬、分析クエリの財務数値、マーケティングクエリの顧客メールアドレスなど。クラウド型のSQLフォーマッタは、リクエストログにすべてのクエリを記録し、ときには「サービス改善」のために保持し、貼り付けられた本番クエリが機密スキーマとデータを漏洩した実際の侵害事案に関与してきました。ブラウザベースのフォーマッタは露出ゼロで、クエリはマシンを離れません。
ブラウザベースの整形は、ページを一度読み込めばオフラインでも動作するため、飛行機の中、インターネットアクセスのないセキュアな環境、またはデータベースクエリを第三者のサービスに貼り付けてはいけない場所でクエリを整形するのに役立ちます。
よくある質問
SQL のキーワードは大文字で書くべきですか?
SQL のキーワード(SELECT、FROM、WHERE)を大文字で、テーブル名やカラム名を小文字で書くのは広く採用されている慣習です。クエリが視覚的に読みやすくなります。多くのスタイルガイドが推奨していますが、データベースエンジンが要求するものではありません。
フォーマットでクエリの実行が変わりますか?
いいえ。空白とインデントは SQL の実行に影響しません。フォーマットは純粋に人間の可読性のためです。ミニファイされたクエリとインデントされたクエリは同じ結果を返します。
どのインデントサイズを使うべきですか?
2 スペースも 4 スペースもどちらも一般的です。チームで使われているものを選び、一貫させてください。ほとんどの SQL フォーマッターはこの設定が変えられます。
SQL はサーバーに送信されますか?
いいえ。フォーマットは完全にブラウザ内で行われます。クエリがデバイスから出ることはありません。