SQLフォーマッタ徹底比較:自動整形で標準化する実践ガイド(CI/CD・プリコミット対応)

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 ServerSSMS拡張として導入容易。自動化の自由度は低め。
dbForge SQL Complete / Studio有料(オンライン版は一部無料)◎ 詳細設定・チーム共有○(コマンドライン/PowerShell)SQL Server中心(製品群で他DBも)設定を外部化しやすくCIで使い回しやすい。IDE統合も強力。
SQLinForm無料○(CLIあり)主要DBに対応コスト重視+CLI前提の構成に向く。クロスプラットフォーム運用が容易。
VS Code拡張(SQL Formatter等)無料○(タスク/拡張)拡張依存IDE内で完結できるが、細かなチーム統一には限界。CIは工夫が必要。

*価格帯は執筆時点の一般的な状況。正式・最新価格は各ベンダー情報を確認してください。

どれを選ぶか:意思決定ガイド(重み付けスコア例)

以下は合意形成の材料としてのです。チーム事情に合わせて重みは調整してください。

評価軸重みSQL PromptdbForgeSQLinFormVS Code拡張
カスタマイズ性30%5543
自動化適性(CLI)25%3554
チーム共有15%5543
パフォーマンス10%4443
方言カバー10%4443
導入コスト10%2255

総合すると、きめ細かさ+チーム生産性を求めるなら 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)標準的で学習コストが低い。差分が分かりやすい
CTEWITH句は1CTE1行頭、AS直後に改行、内部SELECTをインデントスコープが読みやすくなる
JOINJOIN句は行頭、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での強制整形

基本戦略

  1. 設定ファイルをリポジトリ管理:例 ./tools/sqlfmt/profile.json など。
  2. ラッパースクリプトを用意:CLI差を吸収(sqlfmt.sh / sqlfmt.ps1)。
  3. Gitフック:ステージ済みの .sql を対象に整形+再ステージ。
  4. 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.jsonprofile.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、一時テーブル名ドル引用では内部整形を抑制/関数定義のLANGUAGEIMMUTABLEを整列
MySQL`backtick`識別子、LIMIT句、エンジン・コメント識別子クォートの混在を解消/LIMITの改行ルール統一
Oracle PL/SQLブロック終端/、例外句、DECODECASEの混在DDL後の/は触らない/CASEの折り返し基準を固定

「自動整形だけで壊さない」ためのテクニック

  • チェックモード:整形せず差分だけ確認(CIで失敗)を用意。PRでの驚きを減らす。
  • 無害化ルールの優先:最初は空白・改行・大文字小文字のみ。並べ替え(例:列順の自動並替)は段階導入。
  • バイナリ/生成物の除外migrations/**/snapshot.sql 等は除外対象に。
  • 方言スイッチ:DBごとにプロファイルを分け、--dialect tsql|plpgsqlのように切替。
  • 難解SQLの退避:意図的な整形を残す必要があるSQLは-- @formatter:off/on等のコメントで保護(ツールに応じて)。

ロールアウト計画:既存リポジトリを安全に標準化する

  1. Phase 0:現状調査(ファイル数・拡張子・方言の混在度)。
  2. Phase 1:小規模ディレクトリで試行。ルールの最終調整。
  3. Phase 2機械整形のみの一括コミットを1本作る(機能変更なし)。
  4. Phase 3.git-blame-ignore-revsを導入し「整形コミット」を無視。
  5. 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別追加の二層構造に。

導入・運用のポイント(要約)

  1. 自動フォーマットの組み込み:CLI/PS対応のツール(dbForge、SQLinForm等)を選ぶと、GitフックやAzure DevOps/GitHub Actionsでの強制整形が容易。
  2. プロファイル共有:生成した設定ファイル(例:.sqlpromptstyle等)をリポジトリにコミットして全員で参照。
  3. 試用と比較:まず無償やWeb版でルール検証。トライアル期間でCI連携まで試すと後戻りが少ない。
  4. IDE統合 vs 独立ツール:SSMS中心ならSQL Prompt/dbForge、複数IDE・CI主導ならSQLinFormが扱いやすい。

最終結論:推奨フロー

  1. ルール策定:Web版フォーマッタで理想の書式を試作し、サンプル差分でチーム合意。
  2. ツール比較
    • きめ細かい調整+生産性向上 ⇒ SQL Prompt または dbForge SQL Complete
    • 無料で自動化重視 ⇒ SQLinForm
  3. 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方言別プロファイルが分かれている

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次