FlowingDev

SQL解説:キレイ好きなクエリ言語

SQLステートメントを常に同じスタイルでフォーマットすることが、読みやすさ、メンテナンスのしやすさ、そしてチームでの開発にどれだけ重要か、その理由を解説します。

ツールを試す: SQL ビューア

ひと言でいうと

SQLフォーマットとは、SQLコードに一貫したスタイルルールを適用することで、人間にとって読みやすく、デバッグしやすく、メンテナンスしやすくするプラクティスです。

どんな問題を解決するか

構造化クエリ言語(SQL)は、1970年代からデータ操作の王様として君臨してきました。コンピュータがデータベースと対話するために設計され、その仕事を見事にこなします。でも、落とし穴が。データベースエンジンは、あなたの書いたSQLの見た目なんて、これっぽっちも気にしないんです。

コンピュータにとって、これと…

SELECT u.id, p.profile_url, COUNT(c.id) AS comment_count FROM users u JOIN profiles p ON u.id = p.user_id LEFT JOIN comments c ON u.id = c.user_id WHERE u.signup_date > '2023-01-01' GROUP BY u.id, p.profile_url HAVING COUNT(c.id) > 5 ORDER BY comment_count DESC;

…これは、まったく同じものなんです。

select u.id,p.profile_url,count(c.id) as comment_count from users u join profiles p on u.id=p.user_id left join comments c on u.id=c.user_id where u.signup_date>'2023-01-01' group by u.id,p.profile_url having count(c.id)>5 order by comment_count desc;

この柔軟性はマシンにとっては最高ですが、人間の開発者にとっては悪夢でしかありません。クエリが単純な検索から、複数のJOINやサブクエリが絡み合う巨大なモンスターに成長するにつれて、フォーマットされていないSQLは、解読不能なテキストの壁と化します。100行にわたる一塊のクエリからバグを見つけ出したり、ロジックを理解しようとしたりするのは、頭痛の種にしかなりません。

SQLフォーマットは、この人間側の問題を解決します。クエリの論理構造を反映した視覚的な構造をコードに与えるのです。改行やインデント、一貫した大文字・小文字の使い分けを加えることで、ごちゃごちゃに絡まったコードを、明確でざっと目を通せるドキュメントに変身させます。これは、コードをただ「キレイ」にするためだけのものではありません。理解しやすくするためのものなのです。チームメイトへの、そして何より、深夜3時にこのコードをデバッグする羽目になる未来の自分への、プロとしての礼儀なのです。

内部の仕組み

優れたSQLフォーマッタは、単なる検索・置換スクリプトとはわけが違います。コードを書き換える前に、コードを解析して理解する、言語を認識するツールなのです。このプロセスは、一般的に3つの主要なステップで構成されています。

ステップ1:字句解析(別名:トークン化)

まず、フォーマッタはSQLステートメントの生のテキストをスキャンし、それを「トークン」のストリーム(流れ)に分解します。トークンとは、その言語における意味を持つ最小単位のことです。文章を個々の単語や句読点に分解するようなものだと考えてください。

例えば SELECT name FROM users; のような単純なクエリの場合、トークンストリームは次のようになります。

トークンテキスト トークン種別
SELECT KEYWORD
name IDENTIFIER
FROM KEYWORD
users IDENTIFIER
; PUNCTUATION

字句解析器(lexer)は、入力のすべての部分を分類します:キーワード(SELECT、FROM、WHERE)、識別子(users、nameのようなテーブル名やカラム名)、演算子(=、+、>)、リテラル('admin'のような文字列や42のような数値)、そして句読点です。このトークンのストリームが、次のステップの原材料となります。

ステップ2:構文解析と抽象構文木(AST)

トークンのリストは、ただのフラットなシーケンスにすぎません。クエリを真に理解するためには、フォーマッタはその文法構造を理解する必要があります。ここで登場するのが構文解析(parsing)です。パーサはトークンストリームを受け取り、抽象構文木(AST: Abstract Syntax Tree)と呼ばれる階層的なデータ構造を構築します。

ASTはコードの論理構造を表します。ちょうど、文章の図解が主語、動詞、目的語の関係を示すのと同じです。

先ほどの単純なクエリ SELECT name FROM users; の場合、ASTを簡略化すると次のようになります。

- SelectStatement
  - SelectClause
    - SelectItem
      - Identifier: "name"
  - FromClause
    - Table: "users"

WHERE句を持つもっと複雑なクエリの場合、ASTはWhereClauseのための別のブランチを持ち、その中には比較演算子や比較される値を表すノードが含まれます。このツリーが、フォーマッタにとってのクエリの「メンタルモデル」です。もはや単なるテキストの文字列としてではなく、特定の句とコンポーネントを持つSELECTステートメントとして認識しているのです。

ステップ3:ツリーの整形出力(Pretty-Printing)

ここからが魔法の時間です。ASTを手に入れたフォーマッタは、ツリーをノードごとにたどり、それを再び文字列として出力できます。ただし今回は、一貫したルールのセットを適用しながらです。

「Pretty-printer」は、ASTのあらゆる種類のノードに対してルールを持っています。

  • SelectStatementノードを見つけると、新しい行を開始することを知っています。
  • SELECTのようなKEYWORDトークンに遭遇すると、ルールがその大文字・小文字(例:UPPERCASE)を決定します。
  • FromClauseに入ると、FROMを新しい行に出力し、次の部分をインデントすることを知っています。
  • SelectClause内のカラムのリストを見つけると、リストが特定の長さを超えた場合に各カラムを新しい行に配置する、といったルールを持っているかもしれません。
  • 演算子トークンを見つけると、その周りにスペースを追加します(= が = になります)。

このようにASTを体系的にたどりながらルールを適用することで、フォーマッタは最終的なクリーンな出力を構築します。このアプローチが強力なのは、単にテキストのパターンに基づいて推測しているわけではないからです。FROM usersのuserはテーブル名だと理解する一方、'user_profile.jpg'の中のuserは文字列の一部にすぎず、触るべきではないことを知っています。また、パーサは各方言のユニークな構文やキーワードを理解するように設定できるため、フォーマッタはさまざまなSQL方言(例:PostgreSQL, MySQL, T-SQL)を扱うことも可能です。

実録!開発現場の物語

真夜中のデバッグセッション事件

シニアエンジニアのプリヤは、「データベースCPU使用率99%」というPagerDutyのアラートで叩き起こされました。ログインして原因を突き止めると、それはリソースをすべて食いつぶしながらループで実行されている、1つの巨大なSQLクエリでした。そのクエリは1時間前にジュニア開発者によってコミットされたものです。ファイルを開いた彼女は、がっくりと肩を落としました。そこにあったのは、250行にわたるフォーマットされていないSQLの塊で、ネストされたサブクエリ、CASE文、複数のJOINがカオスに入り乱れていました。ロジックを追うのは不可能です。

それを理解しようとする前に、彼女はテキストの塊を丸ごとコピーし、SQLフォーマッタに貼り付けました。すると、あの怪物は一瞬でおとなしくなりました。明確なインデントと改行で整形された出力は、クエリの構造を明らかにしました。そして、そこに、火を見るより明らかにあったのです。巨大なテーブルへのJOINにON句が欠けており、致命的なデカルト積を引き起こしていたのです。彼女は正しいON句を追加して修正をプッシュし、データベースのCPU使用率が正常に戻るのを見届けました。

教訓: フォーマットは単なるスタイルの問題ではありません。デバッグにおける重要な第一歩です。論理構造を可視化し、しばしばその過程でバグそのものを明らかにしてくれるのです。

合併とごちゃ混ぜスタイルの悲劇

2つのスタートアップが合併し、それぞれのエンジニアリングチームが統合されました。「Acme」社のチームはSQLをすべて大文字で書き、末尾カンマを使い、インデントにはタブを使用していました。一方、「Bolt」社のチームは小文字を使い、先頭カンマを使い、インデントには4つのスペースを使用していました。コードレビューは、スタイルに関する果てしない、陰湿な言い争いの場と化しました。「Nit(細かい指摘ですが):ここではキーワードは小文字を使います」が最も一般的なコメントになり、実際のロジックやパフォーマンスに関する議論を完全に脱線させていました。

このスタイル戦争にうんざりした新しいテックリードは、簡単なルールを導入しました。すべてのSQLコードは、マージされる前にCI/CDパイプラインの一部として自動フォーマッタを通さなければならない、というものです。彼は中立的なスタイルガイドでフォーマッタを設定し、それをpre-commitフックに追加しました。すると、議論は一夜にしてなくなりました。コードベースは徐々に統一されていきました。エンジニアたちは今や、コードがどのように見えるかではなく、何をするのかに集中できるようになったのです。

教訓: 自動化された共有フォーマッタは、究極の平和維持軍です。一貫性を強制し、無意味な議論をなくし、チームが重要なことに集中できるようにしてくれます。

コピペができなかったアナリスト

データアナリストのベンは、四半期ごとの売上レポートを生成するために複雑なクエリを実行する必要がありました。エンジニアが彼にクエリをメールで送ってくれました。しかし、ベンがメールクライアントからそれをコピーしてデータベースツールに貼り付けると、めちゃくちゃになってしまいました。メールクライアントがすべての行に>文字を追加し、おかしな改行を挿入し、スマートクォートに変換してしまっていたのです。クエリは大量の構文エラーで失敗しました。

10分間イライラしながら手作業でクリーンアップした後、ベンは社内のツールポータルのことを思い出しました。彼はメールからコピーした>文字などを含むめちゃくちゃなテキスト全体を、SQLビューアに貼り付けました。そのツールは賢くもメールのゴミを無視し、根底にあるSQLを解析して、完璧にクリーンで実行可能なクエリを吐き出してくれたのです。彼はそれを実行し、数秒でデータを得ることができました。

教訓: 堅牢なフォーマッタは、ただの整形ツールではありません。メールやチャットのような、コードを意識しないシステムによってめちゃくちゃにされたコードを救い出すことができる、クリーンアップツールでもあるのです。

よくある間違いと落とし穴

  • 方言の違いを無視する。 Microsoft T-SQLのクエリをPostgreSQLのルールセットでフォーマットするのは悪手です。フォーマッタがTOP 10をLIMIT 10に「修正」してしまい、それがSQL Server上で構文エラーを引き起こすかもしれません。常にフォーマッタが正しいSQL方言に設定されていることを確認してください。
  • 生成されたコードをフォーマットする。 プログラムやORM(Object-Relational Mapper)によって動的に構築されたSQLをフォーマットする際には、細心の注意が必要です。そのアプリケーションは、非常に特殊で(そしてしばしば醜い)文字列構造に依存しているかもしれません。空白を「修正」することで、それを生成または読み取るコードを壊してしまう可能性があります。
  • 「完璧な」スタイルをめぐって議論する。 キーワードを大文字にすべきか小文字にすべきかで何時間も議論するのは非生産的です。常識的なデフォルト(人気のスタイルガイドなど)を選び、ツールにそれを強制させましょう。
  • 悪いロジックを修正するためにフォーマットに頼る。 フォーマッタは、遅くて非効率なクエリを美しく見せることはできますが、速くはしてくれません。フォーマットは悪いロジックを可視化しますが、根本的なパフォーマンスや正確性の問題を修正するのは、依然としてあなた自身です。

なぜアンテナを張っておくべきなのか

データを扱うなら、SQLを扱います。そして、プロとして何らかの形でSQLを扱うなら、その可読性を気にかけるべきです。以下のようなときには、いつでもSQLフォーマットについて考えるべきです。

  • 新しいクエリを書くとき: コミットする前にフォーマットしましょう。同僚への贈り物です。
  • 誰かのコードをレビューするとき: クエリが読みにくい場合、最初の依頼は「これをフォーマッタにかけてもらえますか?」であるべきです。
  • 複雑なクエリをデバッグするとき: 生のコードを読もうとさえしないでください。まずフォーマットしましょう。
  • 新しいプロジェクトに参加するとき: そのチームのSQLスタイルガイドやフォーマッタの設定を探しましょう。チームの標準を素早く学ぶ方法です。
  • **新しいプロジェクトを立ち上げるとき:**初日からフォーマットの標準を確立し、CI/CDパイプラインで自動化しましょう。

要するに、フォーマットは「あると嬉しい」オプションではありません。プロフェッショナルで、保守可能で、協力的なSQLを書くための、基本的な一部なのです。

さらに深く知る

  • Wikipedia: SQL: 言語そのものについてのハイレベルな概要。
  • dbt Labs SQL Style Guide: 現代のデータチームでSQLを書くための、広く評価されている実践的なスタイルガイド。
  • SQLFluff Docs: 人気の高い、設定自由度の高いSQLリンター兼フォーマッタのドキュメント。「Rules」セクションは、設定可能なすべての項目を巡る素晴らしいツアーになります。
  • PostgreSQL: Lexical Structure: 最も人気のあるSQL方言の一つであるPostgreSQLの、公式の文法とトークン化ルールへの深いダイブ。

理論はOK。さあ手を動かそう — 100%ブラウザ内で。

ツールを試す: SQL ビューア