D
开发工具箱

SQL 格式化:把一行挤死人的查询,拆成能喘气的样子

文档转换 2026年6月28日 约 1 分钟阅读

那次评审我读了三遍才看懂

上周看同事提的 SQL,一句查询从 SELECT 一路顶到 ; 全是同一行,两百来个字符,里面嵌套了三个 JOIN、一个 CASE WHEN、还有一长串 AND/OR 条件。我想看清”到底哪张表连哪张表、哪个条件挂在哪个 JOIN 上”,眼睛在屏幕上横着扫了三遍,头都晕了。

评审没通过不是因为逻辑错,是因为没人能在三秒内看懂它在干什么。后来他格式化成多行、关键字全大写,我一眼就看出第二个 JOIN 的条件写反了。从那以后我们组定了规矩:SQL 提交前必须格式化。这篇就讲格式化到底在整理什么,以及压回去(压缩)又是什么场景。

SQL 其实很”讲结构”

和 HTML 不同,SQL 不是靠缩进表达的层级语言——它靠关键字划分段落。一条查询大致是这样一段一段拼起来的:

SELECT 列
FROM 表
JOIN 另一张表 ON 连接条件
WHERE 过滤条件
GROUP BY 分组
HAVING 分组后过滤
ORDER BY 排序
LIMIT 限制条数

每一段(叫”子句”)都是一个独立的意思单元。把它们在同一行挤着写,人脑就得自己去做”分段”,很累;分行写,分段就交给排版,人脑只管理解。

重要前提:SQL 的关键字、函数名本身不区分大小写selectSELECT 对数据库完全一样。大写只是给人看的——这是格式化的第一个价值。

美化:让每个子句各占一行

最基础的格式化,就是把上面那些子句拆到不同行,并且:

  • 列清单(SELECT 后面那一串)每个字段一行;
  • JOIN 另起一行,ON 紧跟其后或再缩进;
  • WHERE 里的 AND/OR 每个条件一行,并且统一缩进,让你看清条件的”归属”。

比如一行挤着的:

SELECT u.id,u.name,o.amount FROM users u JOIN orders o ON u.id=o.user_id WHERE u.age>18 AND o.status='paid' ORDER BY o.amount DESC;

美化后:

SELECT
  u.id,
  u.name,
  o.amount
FROM users u
JOIN orders o
  ON u.id = o.user_id
WHERE
  u.age > 18
  AND o.status = 'paid'
ORDER BY o.amount DESC;

现在”连哪张表""什么条件”一目了然。本站的 SQL 格式化工具在美化时提供两个开关,下面说。

关键字大写:统一”门面”

勾上”关键字大写”,select from where join 全变成 SELECT FROM WHERE JOIN。这不是语法要求,是可读性约定

  • 一眼能区分”关键字”和”表名/列名/别名”——大写的是 SQL 自己的词,小写的是你的业务词。
  • 团队统一后,搜索 WHERE 不会漏掉写成 where 的那处。

如果你更习惯小写风格(有些 ORM 生成的就是小写),关掉这个开关即可,工具只做换行缩进、不碰大小写。

缩进:2 空格、4 空格还是 Tab?

和 HTML 一样,纯风格之争。SQL 的缩进更讲究”语义对齐”——ON 后面的条件通常比 JOIN 再缩进一层,表示”它是这个 JOIN 的附属”;AND/ORWHERE 缩进一层,表示”它是 WHERE 的子条件”。本站工具按这个层级缩进,嵌套子查询时会再往里进。

选 2 还是 4 空格,同样建议团队定一种、别混。

压缩:塞进日志、文档、配置时

美化是为了人读,压缩是为了”省地方”。

有些场景你不想保留那么多换行:

  • 把 SQL 写进应用配置、或者作为单行字符串传给某个 API;
  • 在日志里记录执行过的语句,多行会打乱日志结构;
  • 文档示例里想贴一句短查询,多行太占版面。

压缩做的是:去掉换行和多余空格、把 = 两边空格收掉、注释去掉(注释对运行没用,还暴露意图)。比如美化后的查询压缩回:

SELECT u.id,u.name,o.amount FROM users u JOIN orders o ON u.id=o.user_id WHERE u.age>18 AND o.status='paid' ORDER BY o.amount DESC;

压缩不会改变查询语义,只是把”给人看的结构”抹平。它也不会帮你修逻辑错误——错的查询压短了还是错的。

MySQL、PostgreSQL、SQL Server 的差异

SQL 有个麻烦:标准归标准,各家数据库都有方言。格式化本身(换行、大小写)是通用的,但有些写法你压缩/美化时要注意:

  • 字符串引号:MySQL 和 SQL Server 常用单引号 'paid',双引号在某些库里表示”标识符(列名/表名)“而非字符串。PostgreSQL 严格区分:单引号是字符串,双引号是标识符。工具不会改你的引号,但你写错类型,格式化救不了。
  • 方括号 vs 反引号:SQL Server 用 [column name] 表示带空格的标识符,MySQL 用 `column name`,PostgreSQL 用 "column name"。本站工具识别这些定界符,不会把里面的内容当普通单词拆断。
  • 注释风格-- 单行 三家都支持,/* 多行 */ 也支持。压缩时默认去掉,但生产排查时建议保留关键注释。
  • 关键字集合LIMIT 在 MySQL/PostgreSQL 里常用,SQL Server 用 TOPOFFSET ... FETCH。工具的关键字表覆盖了常见子集,但极端方言函数(如 SQL Server 的 PIVOT、PostgreSQL 的 ILIKE)不会当”关键字大写”,这点心里有数即可。

一句话:格式化是跨数据库的,逻辑方言得自己保证写对。

嵌套查询:格式化最能派上用场的地方

子查询(尤其 FROM 里的派生表、IN 里的集合)是 SQL 最难读的部分。美化时,本站会把子查询整体再缩进一层,并且子查询内部的 SELECT ... FROM ... WHERE 重新按层级排:

SELECT *
FROM (
  SELECT user_id, COUNT(*) AS cnt
  FROM orders
  WHERE status = 'paid'
  GROUP BY user_id
) t
WHERE t.cnt > 5;

不格式化时,这一坨里外分不清;格式化后,“外层筛选 cnt > 5”和”内层统计每个用户订单数”清楚分层。这也是我强烈建议所有含子查询的 SQL 先美化的原因。

常用对照速查

场景该用说明
代码评审提交 SQL美化 + 关键字大写reviewer 三秒看懂
排查长查询的 JOIN 层级美化(4 空格)层级最清楚
含子查询的报表 SQL美化内外分层不晕
写进日志的单行记录压缩不打乱日志结构
文档里贴短示例压缩一行更整洁
团队统一风格关键字大写 + 统一缩进比选哪种更重要

常见问题

Q: 美化之后执行结果变了,为什么?

正常不会。格式化只动空白和大小写,不动语义。如果结果变了,先怀疑是不是原 SQL 本身依赖了某种隐式行为,或者字符串里本来就有意义的大小写/空格被误改——但本站工具不会改引号内的内容,这种概率极低。更常见的是”看起来变了”其实只是你终于看懂了它原本在干什么。

Q: 关键字大写会影响性能吗?

不会。数据库解析时会把关键字归一化,大小写对执行计划毫无影响。大写纯粹是给人看的。

Q: 压缩会去掉我的注释,能保留吗?

本站压缩默认去掉注释(注释对运行无意义,且常暴露内部逻辑)。如果你用注释做临时标记或说明,压缩前请确认——目前压缩模式会清除,需要保留就别走压缩,或者压缩前先备份。

Q: 我的 SQL 是 SQL Server 的 [列名],会被拆坏吗?

不会。工具识别方括号、反引号、双引号三种标识符定界符,里面的内容原样保留,不会当普通单词拆行或改大小写。

Q: 能不能直接格式化再覆盖原文件?

可以,但和 HTML 一样,先在版本控制里提交一次。格式化理论上不改变语义,但团队协作文档里建议保留”格式化前”的版本对照,尤其是历史 SQL。