SQLの可読性・レビュー効率・保守性を高める最短ルートは「チェックイン時の自動整形」です。本記事では、主要なSQLフォーマッタの比較と、CI/CD・プリコミットフックでの強制整形までを一気通貫で解説。ばらばらな規約を一本化し、実装コストと失敗しがちなポイントも回避できる具体策を提示します。
SQLコードのフォーマッタ選定と標準化の全体像
「SQLを綺麗にする」だけでは標準化は完結しません。実務で重要なのは、ルールの合意・ルールを道具として実装する・逸脱を機械的に防ぐという3点セットです。本記事は次の順に進めます。
- 評価観点:何をもって「良いフォーマッタ」とするか
- 主要ツールの比較と向き不向き
- ルール策定〜共有〜自動化の実装パターン(Gitフック/CI)
- データベースごとの方言差・落とし穴と回避策
- 移行・ロールアウト(既存リポジトリへの適用)
評価観点(要件の落とし込み)
要件として挙がりやすい「設定が豊富」「CI/CDやプリコミットで自動化できる」を、意思決定できる粒度に分解します。
| 観点 | 見るポイント | 標準化への寄与 |
|---|---|---|
| カスタマイズ性 | キーワード大文字/小文字、インデント幅、カンマ配置、JOIN/CTE/CASE/サブクエリの折返し、識別子クォート、ヒント句、コメント整形などが細かく制御できるか | 既存の書き味を極力尊重しつつ一本化できる |
| 自動化適性 | CLI/PowerShell/コマンドラインの有無、非対話モード、終了コード、標準入出力対応、コンテナ化の容易さ | Gitフック/CIでの強制が可能 |
| チーム共有 | 設定ファイルの外部化・エクスポート、プロファイルの共有/ロック、IDEとCIで同一設定を使い回せるか | 「環境差」をなくし再現性を確保 |
| パフォーマンス | 大きなDDL/複雑なCTEでも実用的な速度か、並列化の余地 | フックやCIの体験が劣化しない |
| SQL方言の網羅 | T-SQL/PL/pgSQL/PL/SQL/MySQL等の構文・ヒント・バッチ区切り(GO等)への追従 | 多DB混在リポジトリでも破綻しない |
| 導入コスト | 価格、ライセンス形態、導入に伴う学習・運用コスト | 全員が日常的に使える |
主要ツールの比較(2025年11月時点の一般的な状況)
価格は参考帯。正式な価格は各ベンダーの最新情報を確認してください。
| ツール | 価格帯* | カスタマイズ性 | 自動化・CLI | 対応DB/方言 | 備考 |
|---|---|---|---|---|---|
| Redgate SQL Formatter (Web) | 無料 | プリセット中心 | - | 主にT-SQL想定 | ブラウザで手軽。まず理想ルールのたたき台を検証する用途に最適。 |
| Redgate SQL Prompt | 有料 | ◎ プロファイル共有可 | △(PowerShell等で一部自動化) | SQL Server中心 | 補完・リファクタ含む“開発体験”強い。CI自動化は事前検証が必要。 |
| ApexSQL Refactor | 有料(旧無料) | ○ | △(CLI無し) | SQL Server | SSMS拡張として導入容易。自動化の自由度は低め。 |
| dbForge SQL Complete / Studio | 有料(オンライン版は一部無料) | ◎ 詳細設定・チーム共有 | ○(コマンドライン/PowerShell) | SQL Server中心(製品群で他DBも) | 設定を外部化しやすくCIで使い回しやすい。IDE統合も強力。 |
| SQLinForm | 無料 | ○ | ○(CLIあり) | 主要DBに対応 | コスト重視+CLI前提の構成に向く。クロスプラットフォーム運用が容易。 |
| VS Code拡張(SQL Formatter等) | 無料 | △ | ○(タスク/拡張) | 拡張依存 | IDE内で完結できるが、細かなチーム統一には限界。CIは工夫が必要。 |
*価格帯は執筆時点の一般的な状況。正式・最新価格は各ベンダー情報を確認してください。
どれを選ぶか:意思決定ガイド(重み付けスコア例)
以下は合意形成の材料としての例です。チーム事情に合わせて重みは調整してください。
| 評価軸 | 重み | SQL Prompt | dbForge | SQLinForm | VS Code拡張 |
|---|---|---|---|---|---|
| カスタマイズ性 | 30% | 5 | 5 | 4 | 3 |
| 自動化適性(CLI) | 25% | 3 | 5 | 5 | 4 |
| チーム共有 | 15% | 5 | 5 | 4 | 3 |
| パフォーマンス | 10% | 4 | 4 | 4 | 3 |
| 方言カバー | 10% | 4 | 4 | 4 | 3 |
| 導入コスト | 10% | 2 | 2 | 5 | 5 |
総合すると、きめ細かさ+チーム生産性を求めるなら SQL Prompt / dbForge、無料かつ自動化重視なら SQLinForm が本命です。IDE中心運用で“最低限そろえばOK”なら VS Code拡張でも回せますが、CIでの強制統一まで見据えると CLI が強いツールが有利です。
ルール策定:まずWeb版フォーマッタで「合意可能な理想」を可視化
拙速にツールを決めるより、Web版フォーマッタ(例:Redgate SQL Formatter Web)で試作→スクリーンショットと差分付きで提案→レビュー→少数派の違和感を拾う、という流れが成功率を上げます。合意のコツは以下です。
- 最初から100点を狙わず「80点の一貫性」を目標にする
- “読み手のメンタルパース”に着目(JOIN/WHERE/SELECTの塊が視線誘導されるか)
- 「変更しないルール」を先に宣言(例:識別子の大文字小文字は既存踏襲)
- 曖昧な条項は機械に落ちないので削る(例:「適宜改行」は禁止)
推奨ベースライン・スタイル(サンプル)
| カテゴリ | 推奨ルール | 理由 |
|---|---|---|
| キーワード | 大文字(SELECT, FROM, WHERE…) | 視線のアンカーになり差分レビューがしやすい |
| インデント | 2または4スペース。タブは非推奨 | IDEや環境差による崩れを回避 |
| カンマ位置 | 末尾(trailing comma) | 標準的で学習コストが低い。差分が分かりやすい |
| CTE | WITH句は1CTE1行頭、AS直後に改行、内部SELECTをインデント | スコープが読みやすくなる |
| JOIN | JOIN句は行頭、ON句を改行して条件はANDで縦積み | 結合条件の漏れや誤解を防ぐ |
| 関数/引数 | 関数名直後に括弧、引数区切りはスペース後 | 機械的に整形しやすい |
| コメント | — 一行コメント推奨。ブロックは最小限 | 差分での邪魔を最小化 |
| 終端記号 | セミコロン必須(T-SQLでも徹底) | 他方言との相互運用性向上 |
フォーマット前/後のサンプル
前:
select t.id,t.name, count(*) c from dbo.UserTable t left join dbo.Order o on o.user_id=t.id and o.state='paid' where t.is_deleted=0 group by t.id,t.name having count(*)>0 order by c desc
後:
SELECT
t.id,
t.name,
COUNT(*) AS c
FROM dbo.UserTable AS t
LEFT JOIN dbo.[Order] AS o
ON o.user_id = t.id
AND o.state = 'paid'
WHERE
t.is_deleted = 0
GROUP BY
t.id,
t.name
HAVING
COUNT(*) > 0
ORDER BY
c DESC;
運用に効く実装パターン:プリコミット・CI/CDでの強制整形
基本戦略
- 設定ファイルをリポジトリ管理:例
./tools/sqlfmt/profile.jsonなど。 - ラッパースクリプトを用意:CLI差を吸収(
sqlfmt.sh/sqlfmt.ps1)。 - Gitフック:ステージ済みの
.sqlを対象に整形+再ステージ。 - CIで検証:
--checkモードやgit diff --exit-codeで差分が出たら失敗。
ラッパー(共通IF)のイメージ
ベンダーCLIに依存しないための共通インターフェースを定義します。引数は「--config」「--in」「--out」「--check」程度に絞り、内部で各製品のオプションへマッピングします。
# ./tools/sqlfmt.sh(Linux/macOS)
#!/usr/bin/env bash
set -euo pipefail
CMD=${SQLFMT_BACKEND:-"sqlinform"} # sqlinform | dbforge | sqlprompt など
CONFIG=${1:-"./tools/sqlfmt/profile.json"}
MODE=${2:-"fix"} # fix | check
shift 2 || true
case "$CMD" in
"sqlinform")
# 例:実際のCLI呼び出しに置換する
# java -jar ./vendor/sqlinform.jar --config "$CONFIG" --mode "$MODE" "$@"
;;
"dbforge")
# 例:dbForgeのCLI/PSコマンドに置換
;;
"sqlprompt")
# 例:PowerShell経由で整形
;;
*)
echo "Unknown backend: $CMD" ; exit 2 ;;
esac
# ./tools/sqlfmt.ps1(Windows/PowerShell)
param(
[string]$Config = ".\tools\sqlfmt\profile.json",
[ValidateSet("fix","check")][string]$Mode = "fix"
)
$backend = $env:SQLFMT_BACKEND
switch ($backend) {
"sqlinform" { # 実CLIに置換 }
"dbforge" { # 実CLIに置換 }
"sqlprompt" { # 実CLIに置換 }
default { throw "Unknown backend $backend" }
}
プリコミットフック(Bash)
# .git/hooks/pre-commit(実行権限を付与)
#!/usr/bin/env bash
set -euo pipefail
files=$(git diff --cached --name-only --diff-filter=ACM | grep -Ei '\.sql$' || true)
[ -z "$files" ] && exit 0
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
changed=0
for f in $files; do
mkdir -p "$tmp/$(dirname "$f")"
./tools/sqlfmt.sh ./tools/sqlfmt/profile.json fix --in "$f" --out "$tmp/$f"
if ! diff -q "$f" "$tmp/$f" >/dev/null; then
mv "$tmp/$f" "$f"
git add "$f"
echo "formatted: $f"
changed=1
fi
done
if [ $changed -eq 1 ]; then
echo "SQL formatting applied."
fi
プリコミットフック(PowerShell)
# .git/hooks/pre-commit(Windows)
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
".\tools\sqlfmt.ps1 -Config '.\tools\sqlfmt\profile.json' -Mode fix"
GitHub Actions(差分が出たら失敗)
name: sql-format-check
on:
pull_request:
paths:
- '**/*.sql'
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup formatter backend
run: ./tools/install-formatter.sh
- name: Run formatter (check)
run: ./tools/sqlfmt.sh ./tools/sqlfmt/profile.json check --glob "**/*.sql"
- name: Fail if formatting required
run: |
git diff --name-only --exit-code || { echo "::error::SQL formatting required."; exit 1; }
Azure Pipelines(YAML)
trigger: none
pr:
- main
pool:
vmImage: 'windows-latest'
steps:
- checkout: self
- powershell: .\tools\install-formatter.ps1
- powershell: .\tools\sqlfmt.ps1 -Config .\tools\sqlfmt\profile.json -Mode check
- powershell: |
git diff --name-only --exit-code
displayName: 'Fail if formatting required'
Jenkins(Declarative Pipeline)
pipeline {
agent any
stages {
stage('Format Check') {
steps {
sh './tools/sqlfmt.sh ./tools/sqlfmt/profile.json check --glob "**/*.sql"'
}
}
}
post {
always {
script {
sh 'git diff --name-only --exit-code'
}
}
}
}
ポイント:「修正してコミットする」フロー(pre-commit)と、「修正が必要ならCIで失敗」フロー(PRチェック)を両輪で回すと、手元で整形されつつ、万が一の取りこぼしもPR段階で検知できます。
設定ファイルの共有とバージョン管理
- 設定を
./tools/sqlfmt/以下に集約(例:profile.json、profile.xml、.sqlpromptstyle等)。 - IDE(SSMS/VS Code)側も同一設定を参照させ、個人設定の上書きを禁止。
- 設定の変更はPR運用。ルール変更は必ず「理由」と「サンプル差分」を添付。
製品ごとに形式は異なりますが、複数製品を併用する場合は、ベンダー設定 <-> 共通中間表現(YAML/JSON)の対応表を社内Wikiに持つとスムーズです。
IDE統合 vs 独立ツール:現場適合の見極め
- SSMS中心:SQL Prompt / dbForge SQL Complete が自然。IDEで整えてからコミットの文化を作りやすい。
- 複数IDE・CI主導:CLI前提のSQLinFormが取り回しやすい。ヘッドレスで動かす設計に向く。
- VS Code主体:拡張の「保存時整形」を使いつつ、CIではラッパーで同一ルールをチェック。
いずれの場合も「開発者の手元」と「CI/CD」の整形結果が一致することが最重要です。
データベース方言ごとの注意点
| 方言 | 整形時の落とし穴 | 推奨ルール/回避策 |
|---|---|---|
| T-SQL(SQL Server) | GOバッチ区切り、[ ]識別子、TOP句、ヒント句(WITH (NOLOCK)等) | GOを文末扱いにしない/識別子クォート統一/ヒント句の整形位置を固定/セミコロン推奨 |
| PL/pgSQL(PostgreSQL) | ドル引用$func$、RETURN QUERY、一時テーブル名 | ドル引用では内部整形を抑制/関数定義のLANGUAGEやIMMUTABLEを整列 |
| MySQL | `backtick`識別子、LIMIT句、エンジン・コメント | 識別子クォートの混在を解消/LIMITの改行ルール統一 |
| Oracle PL/SQL | ブロック終端/、例外句、DECODEとCASEの混在 | DDL後の/は触らない/CASEの折り返し基準を固定 |
「自動整形だけで壊さない」ためのテクニック
- チェックモード:整形せず差分だけ確認(CIで失敗)を用意。PRでの驚きを減らす。
- 無害化ルールの優先:最初は空白・改行・大文字小文字のみ。並べ替え(例:列順の自動並替)は段階導入。
- バイナリ/生成物の除外:
migrations/**/snapshot.sql等は除外対象に。 - 方言スイッチ:DBごとにプロファイルを分け、
--dialect tsql|plpgsqlのように切替。 - 難解SQLの退避:意図的な整形を残す必要があるSQLは
-- @formatter:off/on等のコメントで保護(ツールに応じて)。
ロールアウト計画:既存リポジトリを安全に標準化する
- Phase 0:現状調査(ファイル数・拡張子・方言の混在度)。
- Phase 1:小規模ディレクトリで試行。ルールの最終調整。
- Phase 2:機械整形のみの一括コミットを1本作る(機能変更なし)。
- Phase 3:
.git-blame-ignore-revsを導入し「整形コミット」を無視。 - Phase 4:プリコミット導入 → CIのチェック有効化 → レビュー指針を更新。
blame無視の設定例
# .git-blame-ignore-revs
# 2025-10-31 SQL auto-format only commit
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
# チーム設定(初回だけ)
git config blame.ignoreRevsFile .git-blame-ignore-revs
ツール別の使いどころと注意
Redgate SQL Formatter (Web)
- ルールのたたき台作成に最適。スクリーンショットと整形差分で議論が早い。
- 自動化は想定外。仕様検証用として割り切る。
Redgate SQL Prompt
- 補完・リファクタ機能で執筆速度が上がる。SSMS中心の組織で強い選択肢。
- CI自動化はPowerShellや外部スクリプトでの工夫が必要。導入前に検証を。
ApexSQL Refactor
- SSMS拡張として使いやすいが、CLIがないためCIの強制統一には不向き。
dbForge SQL Complete / Studio
- 設定の外部化とCLI/PowerShellが揃い、IDEとCIの一致が取りやすい。
- プロファイルを共有リポジトリで管理し、開発PCのIDEへ配布する運用が相性良。
SQLinForm
- 無料かつCLI前提で、プリコミット/コンテナ実行に向く。
- 方言対応は広いが、プロジェクトに合わせた設定チューニングが成功の鍵。
VS Code拡張
- 保存時整形で習慣化しやすい。最初の一歩としては十分。
- 厳密なチーム統一・CI強制までは他ツールの補助が欲しい。
「設定を作る」から「設定を守らせる」へ:実務Tips
- ドキュメントは短く、変更理由とサンプル差分重視(読む気の起きるドキュメント)。
- レビュー観点を整形ルールに寄せる(命名やドメインロジックに集中)。
- 逸脱を機械が止める(CI失敗)。人の善意に頼らない。
- オーナーシップの明確化(ルールの最終決裁者を定める)。
よくある反論と現実解
| 反論 | 現実解 |
|---|---|
| 「開発者の好みがある」 | 好みはIDEローカルで。共有リポジトリは組織の規約。機械が線を引く。 |
| 「既存SQLが巨大で怖い」 | Phase分割と整形専用コミット1本で影響を閉じ込める。blame無視設定で可読性も担保。 |
| 「CIが遅くなる」 | 差分のみ対象・並列化・チェックモード活用。大規模は夜間バッチで全件整形。 |
| 「DBごとにルールが違う」 | プロファイル分割と方言スイッチ。共通最小公倍数+DB別追加の二層構造に。 |
導入・運用のポイント(要約)
- 自動フォーマットの組み込み:CLI/PS対応のツール(dbForge、SQLinForm等)を選ぶと、GitフックやAzure DevOps/GitHub Actionsでの強制整形が容易。
- プロファイル共有:生成した設定ファイル(例:
.sqlpromptstyle等)をリポジトリにコミットして全員で参照。 - 試用と比較:まず無償やWeb版でルール検証。トライアル期間でCI連携まで試すと後戻りが少ない。
- IDE統合 vs 独立ツール:SSMS中心ならSQL Prompt/dbForge、複数IDE・CI主導ならSQLinFormが扱いやすい。
最終結論:推奨フロー
- ルール策定:Web版フォーマッタで理想の書式を試作し、サンプル差分でチーム合意。
- ツール比較:
- きめ細かい調整+生産性向上 ⇒ SQL Prompt または dbForge SQL Complete
- 無料で自動化重視 ⇒ SQLinForm
- CI/CD組み込み:選んだツールのCLIをパイプラインに追加し、整形違反はビルド失敗として標準を強制。
これで、チェックイン時に自動かつ一貫したSQLスタイルが維持され、レビューは本質的なロジックに集中できます。技術的負債化しやすい「表記ゆれ」は、機械に委ねて早期に消し込みましょう。
付録:小技・運用スニペット集
差分対象のみ整形(高速化)
# 直近の差分だけ整形(PR内)
git diff --name-only origin/main...HEAD | grep -Ei '\.sql$' | xargs -I{} ./tools/sqlfmt.sh ./tools/sqlfmt/profile.json fix --in "{}" --out "{}"
整形必須のPRラベルを自動付与(擬似)
# 例:CIで差分があったら "needs-format" というテキストを出力
echo "needs-format" > format.flag
エディタの保存時整形(VS Code設定例のイメージ)
{
"editor.formatOnSave": true,
"[sql]": {
"editor.defaultFormatter": "拡張IDを指定",
"editor.tabSize": 2
}
}
SQLファイル選別(モノレポ対策)
# tools/sql-paths.txtに対象ディレクトリを列挙
xargs -a tools/sql-paths.txt -I{} find {} -type f -name "*.sql" -print0 \
| xargs -0 -I{} ./tools/sqlfmt.sh ./tools/sqlfmt/profile.json check --in "{}"
チェックリスト(配布用ミニ版)
- 設定ファイルがリポジトリにある
- ラッパースクリプト(Linux/Windows)がある
- プリコミット(Bash/PowerShell)が動く
- CIが差分検出で失敗する
- blame無視設定がPRに含まれる
- 難解SQLへの整形オフ注釈が使える
- DB方言別プロファイルが分かれている

コメント