てもとツール
ガイド

SQLが整形できない原因と方言の選び直し方

貼った SQL が整形できない、あるいは整形されたのに読めないときの切り分け手順です。方言によってプレースホルダの読める書き方が変わること、エラーにならずに素通りする入力があること、コメントの扱いで中身が減ることを、実測した件数で示します。

公開読了目安 約5分

この記事の要点

  • 標準SQLが読めるプレースホルダは疑問符だけ
  • 4つの書き方すべてを読める方言は14中2つ
  • 整形が通ってもSQLとは限らない
  • エラーにならない失敗の型が3つある
  • コメントを消す設定は中身を実際に減らす
目次

SQL の整形がうまくいかないとき、原因は 2 つに分かれます。整形が止まる場合と、整形はされたのに読めない場合です。

前者は方言の選び方、後者は入力そのものの問題であることが多いです。この記事では、どちらなのかを切り分ける順番をまとめます。

操作そのものの手順はSQLを読める形に整形する手順にあります。ここでは整形が通らない側を扱います。

止まる原因のほとんどは方言の取り違え

SQL の整形ツールにはたいてい方言の選択肢があります。MySQL や PostgreSQL といった一覧です。

ここを外すと、ごく普通の SELECT 文でも止まります。よく起きるのがプレースホルダの書き方です。

標準SQLを選んだまま $1 を含むSQLを整形したときの表示。1 行 49 桁の「$1」が読めません という見出しの下に、該当行と桁を指すキャレット、そして「この SQL を読めた方言: PostgreSQL / MySQL / MariaDB / Redshift / Snowflake / DuckDB / Trino / Db2」が並んでいる

上の画面は、方言を標準 SQL に固定したまま $1 を含む SQL を整形したものです。文としては何も間違っていません。

それでも止まります。標準 SQL が値の置き場所として認めているのが ? だけだからです。

4 つの書き方が、方言ごとにばらばらに通る

プレースホルダの書き方は主に 4 つあります。?、$1、:name、@name です。

どれが通るかを、SQL整形ツールが選択肢に持つ 14 の方言すべてで実際に試しました。結果が次の表です。

書き方通った方言の数通った方言
?14 中 9標準SQL / PostgreSQL / MySQL / MariaDB / SQLite / BigQuery / DuckDB / Trino / Db2
$114 中 8PostgreSQL / MySQL / MariaDB / Redshift / Snowflake / DuckDB / Trino / Db2
:name14 中 8PostgreSQL / SQLite / SQL Server / Oracle / Snowflake / DuckDB / Trino / Db2
@name14 中 9PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / BigQuery / Redshift / Oracle / Db2

4 つすべてを読めるのは PostgreSQL と Db2 の 2 つだけです。逆に標準 SQL は 4 つのうち 1 つしか読めません。

つまり「よく分からないから標準 SQL のまま」が、いちばん止まりやすい選び方になります。

迷ったら方言を固定しない

同ツールの方言は既定が「自動で探す」です。標準 SQL から順に試し、読めた方言を使います。

自動で探すのまま $1 を含むSQLを整形した結果。上に「方言: PostgreSQL」と出て、SELECT・FROM・WHERE が行頭にそろい、joined_at >= $1 と status = $2 がそのまま残っている

さきほど止まった SQL も、そのままなら PostgreSQL で通ります。どれで読めたかは結果の上に名前で出ます。

方言を固定するのは、出力の細かい違いまで合わせたいときだけで十分です。

整形が通ったのに読めないときの 3 つの型

止まらなかったのに結果がおかしい、という場合もあります。ここからは入力側の問題です。

型 1: そもそも SQL として読まれていない

意外に思われますが、SQL でない文字列を貼ってもエラーになりません。そのまま返ってきます。

「これは日本語です」を貼って整形した結果。出力にも同じ文字列が出ており、その下に「SQL の予約語が見つかりませんでした。整形は行いましたが、SQL として読めているとは限りません。」という断りが表示されている

select from where のような文字列も止まりません。3 行に並び替えられて返ってきます。

ここから言えるのは、整形が通ったことは SQL が正しいことの証明ではないという 1 点です。構文の確認には使えません。

同ツールは予約語が 1 つも見つからないときに断りを出します。ただしこれも予約語の有無を見ているだけで、正しさの判定ではありません。

型 2: コメントが消えている

多くの整形ツールに「コメントを削除する」という設定があります。これを入れたまま使うと、-- や /* */ の中身が消えます。

消えたこと自体は設定どおりです。困るのは、何件消えたかが分からないまま結果をコピーしてしまうことです。

同ツールは既定でコメントを残します。消す設定にしたときだけ「コメントを 2 件取り除きました」と件数を出します。

型 3: 文が 1 つだと思っていたら複数あった

ログからコピーすると、; をまたいで 2 文以上が混ざることがあります。1 文のつもりで読み進めて、途中から別のクエリだった、という取り違えが起きます。

同ツールは ; で区切って数え、2 文以上なら「2 文が含まれています」と出します。文字列やコメントの中の ; は数えません。

値が読めないのは整形の問題ではない

「整形したのに中身が分からない」という詰まり方もあります。これは書式ではなく、値がその場に無いことが原因です。

ORM やフレームワークが出すログは、SQL と値を別の行に書きます。WHERE created_at BETWEEN ? AND ? だけ見ても、いつのデータかは分かりません。

この場合に必要なのは整形ではなく、値を当てる操作です。同ツールでは「値を当てる」を開いてログの値を貼ると、? の位置に入ります。

なお、値を埋めた SQL はログを読むための形です。プレースホルダは値を連結しないための仕組みなので、埋めた形をそのまま実行する用途には向きません。

切り分けの順番

ここまでをまとめると、次の順で見るのが早いです。

  1. 整形が止まったか、通ったかを見る
  2. 止まったなら、まず方言を「自動で探す」に戻す
  3. それでも止まるなら、読めた方言の一覧が出ているかを見る。1 つも出なければ括弧と引用符の閉じ忘れを疑う
  4. 通ったのに読めないなら、予約語の断り・コメントの件数・文の件数を順に見る
  5. 値が分からないだけなら、整形ではなく値を当てる

止まったときに出る行と桁は、整形前の SQL での位置です。整形後の行番号ではないので、手元のエディタでそのまま探せます。

ただし値を当てた場合は別です。値の長さだけ桁が動くので、画面に出る行と桁は値を入れたあとの SQLでの位置になります。そのときは断りが一緒に出ます。

関連するツール

SQL を文字列としてソースへ埋め込むなら、文字列エスケープが続きを引き受けます。1 行にまとめた結果をそのまま渡せます。

設定ファイルの側で同じように行と桁の案内が要るなら、YAML⇔JSON変換とJSON整形ツールが同じ形でエラーを出します。

あわせて読みたい

同じテーマ・関連ツールの記事です。