三、安装 SQLFluff
3.1 pip 安装(推荐)
1# 基本安装
2
3> **本章目标**:掌握本章核心知识点
4> **前置要求**:完成前序章节学习
5> **预计时长**:60 分钟
6
7pip install sqlfluff
8
9# 如果你用的是特定方言,可以安装对应插件
10pip install sqlfluff-templater-dbt # dbt 用户
11
12# 验证安装
13sqlfluff version
3.2 Docker 安装
1# 拉取官方镜像
2docker pull sqlfluff/sqlfluff
3
4# 使用 Docker 运行 lint
5docker run --rm -v $(pwd):/sql sqlfluff/sqlfluff lint /sql/query.sql --dialect mysql
3.3 通过 pipx 安装(隔离环境)
装完之后跑一下 sqlfluff version,能看到版本号就说明安装成功了。
四、基本用法
4.1 sqlfluff lint —— 检查 SQL 文件
假设我们有一个 query.sql 文件:
1select
2 a.id,a.name,
3 b.order_id,
4 b.amount
5from customers a
6join orders b on a.id=b.customer_id
7where a.status='active'
8 and b.amount>100
运行 lint 检查:
1sqlfluff lint query.sql --dialect mysql
输出结果类似:
1== [query.sql] FAIL
2L: 1 | P: 1 | LT01 | Expected only single space before 'select' keyword.
3L: 1 | P: 1 | CP01 | Keywords must be upper case.
4L: 2 | P: 9 | LT01 | Expected single space after comma.
5L: 3 | P: 1 | LT02 | Incorrect indentation.
6L: 6 | P: 1 | AL01 | Implicit/explicit aliasing of table.
7L: 7 | P: 30 | LT01 | Expected single space before and after '='.
8L: 8 | P: 17 | LT01 | Expected single space before and after '='.
9L: 9 | P: 19 | LT01 | Expected single space before and after '>'.
每一行告诉你:哪一行、哪个位置、违反了哪条规则、具体是什么问题。
4.2 sqlfluff fix —— 自动修复
1# 自动修复所有问题
2sqlfluff fix query.sql --dialect mysql
3
4# 只修复特定规则
5sqlfluff fix query.sql --dialect mysql --rules CP01,LT02
6
7# 交互模式,逐个确认
8sqlfluff fix query.sql --dialect mysql --force
修复后的 SQL 自动变成:
1SELECT
2 a.id,
3 a.name,
4 b.order_id,
5 b.amount
6FROM customers AS a
7JOIN orders AS b
8 ON a.id = b.customer_id
9WHERE
10 a.status = 'active'
11 AND b.amount > 100
是不是瞬间清爽了很多?
4.3 sqlfluff parse —— 解析树可视化
1sqlfluff parse query.sql --dialect mysql
这个命令会输出 SQL 的语法解析树,对调试自定义规则特别有用。你可以看到 SQLFluff 如何理解你的 SQL 结构——每一个关键字、标识符、操作符都会被解析成树形节点。
五、配置文件详解
SQLFluff 的配置文件叫 .sqlfluff,放在项目根目录下。下面是一个实战中常用的配置:
1[sqlfluff]
2# 选择你的 SQL 方言
3dialect = mysql
4# 模板引擎(如果用 Jinja2 或 dbt)
5templater = raw
6# 排除的规则
7exclude_rules = AM04, RF02
8# 单行最大长度
9max_line_length = 120
10# 缩进单位
11indent_unit = space
12
13[sqlfluff:indentation]
14# 缩进大小
15indent_unit = space
16tab_space_size = 4
17indented_joins = false
18indented_using_on = true
19
20[sqlfluff:rules:capitalisation.keywords]
21# 关键字大写策略:upper / lower / capitalise / consistent
22capitalisation_policy = upper
23
24[sqlfluff:rules:capitalisation.identifiers]
25# 标识符(表名、列名)小写
26extended_capitalisation_policy = lower
27
28[sqlfluff:rules:capitalisation.functions]
29# 函数名大写
30extended_capitalisation_policy = upper
31
32[sqlfluff:rules:capitalisation.literals]
33# NULL, TRUE, FALSE 大写
34capitalisation_policy = upper
35
36[sqlfluff:rules:aliasing.table]
37# 表别名必须使用 AS 关键字
38aliasing = explicit
39
40[sqlfluff:rules:aliasing.column]
41# 列别名必须使用 AS 关键字
42aliasing = explicit
43
44[sqlfluff:rules:aliasing.length]
45# 别名最短长度
46min_alias_length = 2
47
48[sqlfluff:rules:convention.terminator]
49# SQL 语句必须以分号结尾
50multiline_newline = true
51require_final_semicolon = true
52
53[sqlfluff:rules:layout.long_lines]
54# 长行处理策略
55ignore_comment_lines = true
5.1 方言选择
方言是最重要的配置项。不同的方言在语法细节上差异很大,比如 MySQL 的反引号、PostgreSQL 的 :: 类型转换、BigQuery 的反引号表名等。选错方言会导致误报。
1# MySQL
2dialect = mysql
3
4# PostgreSQL
5dialect = postgres
6
7# SQL Server
8dialect = tsql
9
10# Oracle
11dialect = oracle
12
13# BigQuery
14dialect = bigquery
5.2 排除规则
有些规则可能不适合你的团队,可以直接排除:
1# 在配置文件中排除
2exclude_rules = AM04, LT05, RF02
3
4# 或者在命令行排除
5sqlfluff lint query.sql --exclude-rules AM04,LT05
也可以在 SQL 文件中用注释临时禁用:
1-- noqa: CP01
2select * from users;
3
4-- 禁用整行的所有规则
5select * from users; -- noqa
六、最实用的 10 条规则详解
规则 1:CP01 —— 关键字大小写
问题 SQL:
1select id, name from users where status = 'active';
修复后:
1SELECT id, name FROM users WHERE status = 'active';
配置:
1[sqlfluff:rules:capitalisation.keywords]
2capitalisation_policy = upper
这是最基础也是争议最多的规则。我的建议是:关键字统一大写,标识符统一小写,这是业界最常见的做法。
规则 2:CP02 —— 标识符大小写
问题 SQL:
1SELECT UserId, UserName FROM Users;
修复后:
1SELECT userid, username FROM users;
这条规则确保表名和列名的大小写一致。注意,如果你的数据库是大小写敏感的(比如 PostgreSQL 默认行为),这条规则更加重要。
规则 3:LT02 —— 缩进规范
问题 SQL:
1SELECT
2id,
3 name,
4 email
5FROM
6users
7WHERE
8 status = 'active';
修复后:
1SELECT
2 id,
3 name,
4 email
5FROM
6 users
7WHERE
8 status = 'active';
统一的缩进让 SQL 的层次结构一目了然。
规则 4:AL01 —— 表别名必须显式
问题 SQL:
1SELECT u.id, o.amount
2FROM users u
3JOIN orders o ON u.id = o.user_id;
修复后:
1SELECT u.id, o.amount
2FROM users AS u
3JOIN orders AS o ON u.id = o.user_id;
显式的 AS 关键字让别名定义更清晰,不容易和其他语法混淆。
规则 5:AL02 —— 列别名必须显式
问题 SQL:
1SELECT
2 COUNT(*) total_count,
3 SUM(amount) total_amount
4FROM orders;
修复后:
1SELECT
2 COUNT(*) AS total_count,
3 SUM(amount) AS total_amount
4FROM orders;
规则 6:LT01 —— 空格规范
问题 SQL:
1SELECT id,name,email FROM users WHERE id=1 AND status='active';
修复后:
1SELECT id, name, email FROM users WHERE id = 1 AND status = 'active';
操作符前后加空格,逗号后面加空格。这条规则对可读性提升巨大。
规则 7:LT09 —— SELECT 目标每行一个
问题 SQL:
1SELECT id, name, email, phone, address, city, country FROM users;
修复后:
1SELECT
2 id,
3 name,
4 email,
5 phone,
6 address,
7 city,
8 country
9FROM users;
当选择多个列时,每个列单独一行,方便后续增删改和代码 diff 对比。
规则 8:ST06 —— SELECT 通配符
问题 SQL:
1SELECT * FROM users WHERE status = 'active';
SQLFluff 会提示你避免使用 SELECT *,因为:
- 不清楚实际返回了哪些列
- 表结构变更时容易出问题
- 性能可能受影响
建议改为:
1SELECT id, name, email, status FROM users WHERE status = 'active';
规则 9:AM04 —— GROUP BY 列引用
问题 SQL(某些方言下):
1SELECT
2 department,
3 COUNT(*) AS cnt
4FROM employees
5GROUP BY 1;
修复后:
1SELECT
2 department,
3 COUNT(*) AS cnt
4FROM employees
5GROUP BY department;
用列名代替位置编号,避免调整列顺序后 GROUP BY 出错。
规则 10:CV03 —— 尾部逗号
问题 SQL:
1SELECT
2 id
3 , name
4 , email
5FROM users;
修复后(根据配置可以是前置或后置):
1SELECT
2 id,
3 name,
4 email
5FROM users;
前置逗号还是后置逗号,这又是一个经典的 holy war。SQLFluff 让你通过配置来统一团队标准,不用再吵了。
七、团队集成:从个人工具到团队规范
SQLFluff 最大的价值不在于个人使用,而在于团队统一。下面介绍几种主流的集成方式。
7.1 Pre-commit Hook(推荐)
pre-commit 是 Python 生态最流行的 Git Hooks 管理工具。配合 SQLFluff,可以在每次提交前自动检查 SQL 文件。
首先安装 pre-commit:
然后在项目根目录创建 .pre-commit-config.yaml:
1repos:
2 - repo: https://github.com/sqlfluff/sqlfluff
3 rev: 3.3.1 # 使用最新版本号
4 hooks:
5 - id: sqlfluff-lint
6 name: sqlfluff-lint
7 description: 'Lint SQL files with SQLFluff'
8 # 指定额外参数
9 args: ['--dialect', 'mysql']
10 # 只检查 SQL 文件
11 types: [sql]
12 # 如果你还想自动修复,可以加上 fix hook
13 - id: sqlfluff-fix
14 name: sqlfluff-fix
15 description: 'Fix SQL files with SQLFluff'
16 args: ['--dialect', 'mysql', '--force']
17 types: [sql]
安装 hook:
从此以后,每次 git commit 包含 .sql 文件时,SQLFluff 会自动检查。不通过的话,commit 会被拒绝,开发者必须修复后才能提交。
小技巧:如果项目中已有大量不规范的 SQL,可以先用 sqlfluff fix 全量修复一次,提交一个「格式化」的 commit,再启用 pre-commit hook。
7.2 GitHub Actions CI/CD 集成
在 CI/CD 中集成 SQLFluff,可以确保 PR 中的 SQL 变更一定符合规范。
创建 .github/workflows/sqlfluff.yml:
1name: SQLFluff Lint
2
3on:
4 pull_request:
5 paths:
6 - '**/*.sql'
7 - '.sqlfluff'
8
9jobs:
10 sqlfluff-lint:
11 runs-on: ubuntu-latest
12 steps:
13 - name: Checkout code
14 uses: actions/checkout@v4
15
16 - name: Set up Python
17 uses: actions/setup-python@v5
18 with:
19 python-version: '3.11'
20
21 - name: Install SQLFluff
22 run: pip install sqlfluff==3.3.1
23
24 - name: Run SQLFluff Lint
25 run: sqlfluff lint . --dialect mysql --format github-annotation
26
27 # 可选:将结果作为 PR 评论
28 - name: Run SQLFluff Lint (详细输出)
29 if: failure()
30 run: sqlfluff lint . --dialect mysql --format human
--format github-annotation 参数会让 lint 结果直接显示在 PR 的文件变更页面上,非常直观。
如果你用 GitLab CI,配置也类似:
1# .gitlab-ci.yml
2sqlfluff-lint:
3 image: python:3.11-slim
4 stage: test
5 before_script:
6 - pip install sqlfluff==3.3.1
7 script:
8 - sqlfluff lint . --dialect mysql
9 only:
10 changes:
11 - '**/*.sql'
12 - '.sqlfluff'
7.3 VS Code 集成
安装 VS Code 扩展 SQLFluff(搜索 sqlfluff 即可找到),安装后可以获得:
- 实时 lint 提示(红色波浪线标记问题)
- 保存时自动修复
- 状态栏显示违规数量
在 VS Code 的 settings.json 中添加:
1{
2 "sqlfluff.dialect": "mysql",
3 "sqlfluff.linter.run": "onSave",
4 "sqlfluff.format.enabled": true,
5 "sqlfluff.executablePath": "sqlfluff",
6 "editor.formatOnSave": true,
7 "[sql]": {
8 "editor.defaultFormatter": "dorzey.vscode-sqlfluff"
9 }
10}
这样每次保存 .sql 文件时,SQLFluff 会自动格式化代码——体验和 Prettier 格式化 JavaScript 一样丝滑。
7.4 JetBrains IDE 集成
如果你用 DataGrip 或 IntelliJ IDEA,可以通过 External Tools 或 File Watchers 实现类似效果:
- 打开
Settings > Tools > External Tools
- 添加一个新工具:
- Program:
sqlfluff
- Arguments:
fix $FilePath$ --dialect mysql --force
- Working directory:
$ProjectFileDir$
- 绑定快捷键即可一键格式化
八、自定义规则
SQLFluff 内置了 60+ 条规则,覆盖了绝大多数场景。但如果你的团队有特殊的编码规范,可以编写自定义规则。
8.1 通过配置自定义
大部分需求可以通过配置来实现,不需要写代码。比如:
1[sqlfluff]
2# 组合使用多个配置来定义团队规范
3dialect = mysql
4max_line_length = 100
5exclude_rules = AM04, RF02, ST06
6
7[sqlfluff:rules:capitalisation.keywords]
8capitalisation_policy = upper
9
10[sqlfluff:rules:capitalisation.identifiers]
11extended_capitalisation_policy = lower
12
13[sqlfluff:rules:aliasing.table]
14aliasing = explicit
15
16[sqlfluff:rules:aliasing.column]
17aliasing = explicit
18
19[sqlfluff:rules:convention.count_rows]
20# 推荐使用 COUNT(*) 而不是 COUNT(1)
21prefer_count_1 = false
8.2 编写 Python 自定义规则
如果内置配置满足不了你,SQLFluff 支持用 Python 编写自定义规则插件。
创建一个规则插件 sqlfluff_custom_rules.py:
"""自定义 SQLFluff 规则示例。"""
from sqlfluff.core.rules import BaseRule, LintResult, RuleContext
class Rule_Custom_L001(BaseRule):
"""禁止在 WHERE 条件中使用函数包裹索引列。
1这条规则检查 WHERE 子句中是否对列使用了函数,
2例如 WHERE YEAR(create_time) = 2026,
3这样会导致索引失效。
4"""
5
6groups = ("all",)
7name = "custom_l001"
8description = "避免在 WHERE 条件中对列使用函数(可能导致索引失效)"
9
10def _eval(self, context: RuleContext) -> LintResult | None:
11 # 检查逻辑
12 if context.segment.is_type("function"):
13 parent = context.parent_stack[-1] if context.parent_stack else None
14 if parent and parent.is_type("where_clause"):
15 return LintResult(
16 anchor=context.segment,
17 description="WHERE 条件中对列使用函数可能导致索引失效,"
18 "考虑改写 SQL 或使用函数索引。",
19 )
20 return None
然后在 .sqlfluff 中引用:
1[sqlfluff]
2plugin_host_install_path = /path/to/plugins
当然,大多数团队用内置规则就够了。自定义规则更适合有特殊合规要求的金融、医疗等行业场景。
九、SQLFluff vs 其他工具
| 特性 | SQLFluff | pgFormatter | sql-formatter | sqlfmt |
|---|
| 语言 | Python | Perl | JavaScript | Python |
| 方言支持 | 20+ | 仅 PostgreSQL | 多种(有限) | 仅部分 |
| Lint(检查) | 是 | 否 | 否 | 否 |
| Fix(修复) | 是 | 是(仅格式化) | 是(仅格式化) | 是 |
| 规则可配置 | 是(60+规则) | 有限 | 有限 | 极少 |
| 自定义规则 | 是(Python 插件) | 否 | 否 | 否 |
| Pre-commit | 是 | 社区维护 | 社区维护 | 是 |
| CI/CD 集成 | 原生支持 | 需自行集成 | 需自行集成 | 需自行集成 |
| dbt 支持 | 是 | 否 | 否 | 是 |
| GitHub Stars | 8k+ | 2k+ | 5k+ | 1k+ |
总结一下:
- 如果你只需要格式化 PostgreSQL,
pgFormatter 够用
- 如果你在前端项目中偶尔格式化 SQL 字符串,
sql-formatter(npm 包)更方便
- 如果你需要 完整的 Lint + Fix + 多方言 + CI 集成,SQLFluff 是目前的最佳选择
- 如果你是 dbt 用户,SQLFluff 有原生的 dbt templater 支持,这是其他工具没有的
十、落地实践建议
根据我在多个团队推行 SQL 规范的经验,以下是一些实用的建议:
10.1 渐进式推行,不要一步到位
不要指望一下子启用所有规则。推荐的节奏:
- 第一周:只启用关键字大写(CP01)和基本缩进(LT02)这两条规则
- 第二周:加上别名显式化(AL01、AL02)和空格规范(LT01)
- 第三周:加上每行一列(LT09)和分号结尾(CV03)
- 第四周:启用完整规则集,对于不适合的规则加入 exclude
10.2 先全量格式化,再启用 Hook
对于已有大量 SQL 文件的项目:
1# 1. 先全量修复
2sqlfluff fix . --dialect mysql --force
3
4# 2. 提交一个 formatting-only 的 commit
5git add -A
6git commit -m "style: 统一 SQL 代码格式(SQLFluff)"
7
8# 3. 再启用 pre-commit hook
9pre-commit install
这样做的好处是,格式化相关的 git blame 都指向同一个 commit,不会污染正常的提交历史。
10.3 配置文件纳入版本控制
.sqlfluff 配置文件和 .pre-commit-config.yaml 一定要提交到 Git 仓库。这样团队所有成员用的是同一套规则,不会出现「在我机器上能通过」的问题。
10.4 处理遗留代码
对于实在改不动的历史存储过程,可以用 -- noqa 注释跳过:
1-- 历史遗留存储过程,暂不修改格式
2-- noqa: disable=all
3CREATE PROCEDURE legacy_proc()
4BEGIN
5 -- 这里面的代码不会被 SQLFluff 检查
6 select * from old_table where Flag=1;
7END;
8-- noqa: enable=all
10.5 定期更新 SQLFluff 版本
SQLFluff 还在快速迭代中,新版本会修复 bug、新增规则、提升性能。建议每个季度更新一次版本,但更新前先在本地跑一遍全量 lint,确保新版本没有引入不兼容的变更。
1# 查看当前版本
2sqlfluff version
3
4# 升级到最新版
5pip install --upgrade sqlfluff
6
7# 升级后全量检查
8sqlfluff lint . --dialect mysql
总结
SQL 代码规范看起来是小事,但它直接影响团队协作效率和代码可维护性。SQLFluff 作为目前最完善的 SQL Linter,具备了落地 SQL 规范体系所需的一切:
- 支持主流数据库方言
- 60+ 条可配置规则
- 自动修复能力
- 完善的 CI/CD 集成方案
- 活跃的社区和持续的更新
与其每次 Code Review 的时候手动指出格式问题,不如让工具来做这件事。把精力省下来,花在真正重要的业务逻辑审查上。
如果你的团队还没有 SQL 规范,现在就是最好的开始时间。从 pip install sqlfluff 开始,一步步建立起你们的 SQL 代码质量体系吧。