【SQL】SQL Linter ~ sqlfmt ~

■ はじめに

https://dk521123.hatenablog.com/entry/2024/02/28/225002

の続き。

SQL の Linter (リンター) で「SQLFluff」がでてくるが、
どうも「sqlfmt」と併用して使うことも多いみたいなので
調べてみた。

目次

【1】sqlfmt
【2】環境構築
【3】Lint 種類
 1)--check
 2)--diff
【4】Options
 1)--exclude
【5】使用上の注意
 1)出力は、標準エラー出力で行われている

【1】sqlfmt

* dbt SQLファイルのフォーマッター

https://sqlfmt.com/

【2】環境構築

sudo pip install 'shandy-sqlfmt[jinjafmt]'

sqlfmt --version

https://docs.sqlfmt.com/getting-started/installation

【3】Lint 種類

Lint Explanations
--check 違反してたらFail
--diff 違反している部分の差分表示

1)--check

* チェックし、違反してたらFailする

コマンド例

$ mkdir ~/sqls

# 動作確認用SQL生成 (SELECTの前に空白行)
$ echo "  SELECT a  +  b FROM tbl;  " > ~/sqls/test.sql

$ sqlfmt --check ./sqls
1 file failed formatting check.
0 files passed formatting check.
sqls/test.sql failed formatting check.

2)--diff

* 違反している部分の差分表示

コマンド例

$ sqlfmt --diff ./sqls
1 file failed formatting check.
0 files passed formatting check.
sqls/test.sql failed formatting check.
--- source_query
+++ formatted_query
@@ -1 +1,3 @@
-  SELECT a  +  b FROM tbl;
+select a + b
+from tbl
+;

【4】Options

$ sqlfmt --help
Usage: sqlfmt [OPTIONS] [FILES]...

Options

Options Explanations
--version バージョン表示
--exclude TEXT 除外パスの指定(glob.glob の形式。 e.g. --exclude "**/tests/**")
--encoding TEXT エンコード
--fast / --safe --fast指定した場合、SaftyチェックOFF。--safe指定した場合、Saftyチェック強制ON
--single-process シングルプロセス指定
-k, --reset-cache キャッシュのクリア
--single-process シングルプロセス指定
--no-jinjafmt jinja タグはフォーマットしない
-l, --line-length INTEGER 最大行数 (デフォルト:88)
-v, --verbose 詳細表示
-q, --quiet 標準エラーstderrに極力少ない情報で出力
--no-progressbar 標準エラーstderrにプログレスバー非表示
--no-color カラーコード非表示
--force-color カラーコードを強制表示
-d, --dialect [polyglot or clickhouse] https://docs.sqlfmt.com/dialects/
--help ヘルプ表示

https://docs.sqlfmt.com/getting-started/configuring-sqlfmt

1)--exclude

* 除外パスの指定(glob.glob の形式。 e.g. --exclude "**/tests/**")

フォルダ構成

sqls/
├── targets
│   ├── target1.sql << レビュー対象
│   └── tests
│       └── test2.sql << レビュー対象外
└── tests
    └── test1.sql << レビュー対象外

3 directories, 3 files

コマンド例

# Case1:「--exclude "*/tests/*"」で「tests」配下のものをレビュー対象外
$ sqlfmt --check --exclude "*/tests/*" ./sqls
2 files failed formatting check.
0 files passed formatting check.
sqls/targets/target1.sql failed formatting check.
sqls/targets/tests/test2.sql failed formatting check. < ただし、深い階層ではない除外されない

# Case2:「--exclude "**/tests/**"」で深い階層のものも含めて除外
$ sqlfmt --check --exclude "**/tests/**" ./sqls
1 file failed formatting check.
0 files passed formatting check.
sqls/targets/target1.sql failed formatting check. < 対応できた

【4】使用上の注意

1)出力は、標準エラー出力で行われている

sqlfmt --diff の結果をファイル出力しようと、
「>」で出力させようとしたが、ダメだった。

 原因は、標準エラーだったので、
「2>」で、標準エラーの出力先を
ファイルへ変更する必要があった

【NG】ファイル出力されない例

# 以下だとファイル出力されない
sqlfmt --diff ./sqls > result.txt
sqlfmt --diff ./sqls 2>&1 > result.txt

【OK】ファイル出力したい場合

# 「2>」で、標準エラーの出力先をファイルへ変更する
$ sqlfmt --diff ./sqls 2> result.txt

参考文献

https://zenn.dev/tenajima/articles/217046072b5dba
https://hyodo.tokyo/hyodo/VSCode-sqlfmt-90776954b8a74f8fb41a2bb5ce1ac744

関連記事

SQL Linter ~ SQLFluff ~
https://dk521123.hatenablog.com/entry/2024/02/28/225002
Github Actions ~ SQL Linter ~
https://dk521123.hatenablog.com/entry/2024/03/04/180308