如何格式化 SQL 查询
混乱的SQL是引入错误的最快方式之一。当查询是没有缩进的单个长行时,很难看出哪些条件适用于哪些连接、子查询从哪里开始和结束,或者逻辑是否正确。基于浏览器的格式化工具在本地处理整个工作,而无需将您的查询上传到服务器。
为什么格式化很重要
- 调试:格式良好的查询使逻辑错误可见。您可以从SELECT到WHERE到JOIN跟踪流程,而无需猜测。
- 代码审查:审查人员可以在几秒钟内阅读格式化的SQL。单行查询迫使他们首先在脑海中解析它。
- 维护:当您几个月后重新查看查询时,格式化一目了然地告诉您它在做什么。
- 协作:团队中一致的格式化意味着每个人都以相同的方式阅读SQL。
- 入职:新团队成员可以阅读格式化的SQL,而无需每个查询的口头历史。
- 文档:当SQL出现在设计文档、运行手册或维基中时,格式化的查询对非开发人员来说更容易理解。
- 版本控制差异:格式化的SQL在您更改一个子句而不重新格式化整个查询时会产生更清洁的差异。
如何格式化SQL
- 粘贴您的SQL:将缩小或混乱的查询输入格式化工具。它处理SELECT、INSERT、UPDATE、DELETE、CREATE TABLE,以及带有子查询和连接的复杂查询。
- 配置选项:选择缩进大小以及是否将关键字大写。这些设置与您项目的样式指南相匹配。
- 复制结果:格式化的SQL已准备好粘贴回您的编辑器、数据库客户端或文档中。
好的格式化是什么样的
像select u.name, o.total from users u join orders o on u.id = o.user_id where o.total > 100 and u.active = 1 order by o.total desc这样的查询变成:
SELECT
u.name,
o.total
FROM users u
JOIN orders o
ON u.id = o.user_id
WHERE o.total > 100
AND u.active = 1
ORDER BY o.total DESC
每个子句都从自己的一行开始。条件在其父子句下缩进。连接和它们的ON条件清楚地配对。
SQL格式化约定的简史
SQL由IBM研究人员Donald Chamberlin和Raymond Boyce于1974年创建,最初称为SEQUEL(Structured English Query Language)。原始名称中的「QL」反映了语言读起来像英语的意图。从一开始,这种人类可读的设计就暗示了一种约定:缩进您的子句,使它们像句子一样从上到下阅读。
在20世纪80年代和90年代的大部分时间里,SQL是在文本编辑器中手工编写的,格式化是个人化的。一些工作室采用「河流风格」(每个关键字垂直对齐到虚拟列的右侧),其他人使用「埃及风格」(同行括号等效),大多数只是使用作者喜欢的任何东西。
第一个广泛使用的SQL格式化工具是Apex SQL Formatter(2000年),其次是Devart的SQL Complete(2002年)和Red Gate的SQL Prompt(2003年)。这些工具为SQL Server和Oracle开发人员带来了IDE级别的格式化。到2010年,每个主要的IDE(SSMS、DataGrip、DBeaver)都内置了SQL格式化,在线格式化工具成为临时清理的标准。
2017年,格式化工具生态系统随着sql-formatter(npm)而改变,这是一个开源JavaScript库,为今天包括这个在内的大多数基于浏览器的SQL格式化工具提供支持。现代格式化工具处理方言差异(MySQL反引号、PostgreSQL窗口函数、SQL Server方括号)并产生一致、可配置的输出。
大型公司使用的SQL样式指南
大多数专业代码库遵循几种已发布的SQL样式指南之一:
| 样式指南 | 起源 | 关键约定 |
|---|---|---|
| Mozilla SQL Style | Mozilla | 大写关键字,snake_case名称,2空格缩进 |
| GitLab SQL Style | GitLab数据团队 | 大写关键字,小写名称,4空格缩进,前导逗号 |
| Holistics SQL Style | Holistics | 大写关键字,snake_case,2空格,尾随逗号 |
| Simon Holywell SQL | 个人/流行 | 「河流」对齐,大写关键字 |
| dbt SQL Style | dbt Labs | 小写关键字(现代方言),snake_case,前导逗号 |
| PostgreSQL Wiki Style | PostgreSQL社区 | 小写关键字,snake_case,K&R风格缩进 |
如果您正在开始一个新项目,请选择已建立的指南之一。如果您加入现有代码库,请遵循已有的内容。项目内的一致性比任何特定风格都更重要。
常见格式化选择
- 关键字大小写:大写(最常见,使关键字视觉上独特)、小写(现代dbt/Snowflake风格)或原始大小写(某些IDE保留您输入的内容)。
- 标识符大小写:snake_case是PostgreSQL和大多数Unix友好数据库的默认值;PascalCase或camelCase在Oracle/SQL Server传统中。
- 缩进:2个空格(紧凑,适合80字符终端)、4个空格(匹配大多数代码样式指南)或制表符(SQL中很少见)。
- 逗号位置:尾随逗号(在每列后单独一行)或前导逗号(在下一行开头的逗号,更容易添加/删除列)。
- 行长度:80个字符(终端友好)、120个字符(现代IDE默认)或无限制(在生产中不太常见)。
- JOIN风格:ANSI JOIN关键字(首选)与旧式逗号分隔FROM与WHERE连接条件(已弃用)。
- 子查询格式化:在括号内缩进子查询,使用公共表表达式(CTE)以提高清晰度,或使用显式别名嵌套。
方言差异
SQL格式化工具需要处理特定于方言的语法:
| 方言 | 独特功能 |
|---|---|
| PostgreSQL | 窗口函数、LATERAL JOIN、美元引号字符串($$)、CTE密集型风格 |
| MySQL/MariaDB | 反引号标识符、LIMIT子句语法、REPLACE INTO |
| SQL Server (T-SQL) | 方括号标识符、TOP子句、OUTPUT子句、MERGE |
| Oracle (PL/SQL) | DUAL表、ROWNUM、分层CONNECT BY、点后缀包调用 |
| SQLite | 有限类型系统、REPLACE/UPSERT、单文件数据库 |
| Snowflake | 变体数据类型、QUALIFY子句、COPY INTO |
| BigQuery | 反引号标识符、ARRAY/STRUCT类型、EXCEPT/REPLACE列列表 |
| Redshift | 源自PostgreSQL但有独特的DDL,从S3的COPY |
一个好的格式化工具检测或接受方言提示,然后处理其他方言会拒绝的语法。
常见陷阱
- 在生产脚本中重新格式化:在已经部分应用的迁移脚本中更改空格可能会导致问题,如果您的迁移工具通过哈希指纹。在第一次运行之前格式化。
- 字符串字面量被重新格式化:查询中的多行字符串不应由SQL格式化工具重新格式化;一些幼稚的格式化工具会破坏内联字符串。
- 注释丢失或位置错误:SQL注释(单行破折号和多行斜杠星号)需要在格式化中保留。一些格式化工具会丢弃它们或以令人困惑的方式移动它们。
- 标识符引用更改:PostgreSQL中的双引号标识符或MySQL中的反引号标识符具有特定含义。通过删除引号「规范化」的格式化工具可能会改变查询的行为,如果标识符需要引号(保留字、PostgreSQL中的混合大小写)。
- 窗口函数格式错误:OVER (PARTITION BY x ORDER BY y)应保持可读。在窗口函数括号内积极换行会产生混乱的输出。
- CTE链过度缩进:WITH cte1 AS (...), cte2 AS (...)可能被一些格式化工具嵌套得太深。大多数现代格式化工具将CTE保持在顶层。
- 美元引号字符串(PostgreSQL函数):用$$包装的函数体不应重新格式化其内容。一些格式化工具会破坏它们。
- 供应商特定的关键字分类错误:不知道QUALIFY(Snowflake)或LATERAL(PostgreSQL)的格式化工具可能无法正确大写或对齐它们。
- 带控制流的存储过程:T-SQL或PL/SQL中的BEGIN/END、IF/THEN/ELSE块需要与纯查询不同的缩进规则。
提示
- 提交前格式化:在将SQL添加到版本控制之前,通过格式化工具运行您的SQL。这使差异保持干净,审查集中在逻辑上,而不是风格上。
- 使用一致的关键字大小写:选择大写或小写关键字,并在整个项目中坚持使用。混合风格使查询更难阅读。
- 分解复杂查询:如果一个查询在格式化后仍然难以阅读,请考虑将其分解为CTE(公共表表达式)或视图。格式化无法修复基本上复杂的逻辑。
- 检查语法高亮:一个好的格式化工具提供颜色编码的高亮显示,使关键字、字符串和数字在视觉上独特,这有助于捕获拼写错误。
- 仅格式化您更改的内容:在大型现有代码库中,一次性重新格式化所有内容会产生一个巨大的差异,掩盖真正的更改。在触及查询时增量格式化。
- 设置您的编辑器:VS Code(SQLTools、vscode-sql-formatter)、DataGrip、DBeaver和pgAdmin都有内置或基于扩展的格式化工具。配置一次,然后忘记。
- 注意区分大小写的数据库:PostgreSQL对引用的标识符区分大小写。更改引用标识符大小写的格式化工具将破坏查询。
- 测试格式化的查询:重新格式化后,运行查询以验证输出未更改。大多数格式化工具是可靠的,但格式化工具中的错误可能会破坏查询。
- 使用CTE而不是嵌套子查询:CTE链几乎总是比等效的嵌套子查询更容易阅读和调试,即使格式化后也是如此。
隐私和机密查询
SQL格式化工具完全在您的浏览器中运行。您粘贴的查询、中间处理和格式化的输出都保留在您的设备上。没有任何内容上传到服务器、记录或与任何人共享。
这很重要,因为SQL查询通常包含极其敏感的信息:揭示产品架构的表名、暴露业务逻辑和指标的列名、WHERE子句中真实的客户ID、存储过程中的内部API端点、测试数据中的SSN和信用卡号、HR查询中的员工薪酬、分析查询中的财务数据、营销查询中的客户电子邮件地址。云SQL格式化工具记录其请求日志中的每个查询,有时为「服务改进」保留它们,并参与了真正的违规行为,其中粘贴的生产查询泄露了敏感的架构和数据。基于浏览器的格式化工具没有任何暴露:查询永远不会离开您的机器。
基于浏览器的格式化在页面加载后也可以离线工作,对于在飞机上、在没有互联网访问的安全环境中,或在任何您不能或不应将数据库查询粘贴到第三方服务的地方格式化查询很有用。
常见问题
SQL 关键字应该大写吗?
将 SQL 关键字大写(SELECT、FROM、WHERE)而将表或列名小写是广泛遵循的约定。这让查询在视觉上更易读。大多数风格指南都推荐这样做,但没有数据库引擎强制要求。
格式化会改变查询的执行吗?
不会。空白和缩进对 SQL 执行没有影响。格式化纯粹是为了人类可读性。压缩的查询和缩进的查询产生相同的结果。
应该使用什么缩进大小?
2 或 4 空格都常见。选择您团队使用的并保持一致。大多数 SQL 格式化器允许您配置。
我的 SQL 会发送到服务器吗?
不会。格式化完全在您的浏览器中进行。您的查询从不离开您的设备。