SQL格式化工具

把挤成一行的 SQL 按关键字断行缩进,53 个关键字统一大写,子查询整体缩进一级,引号内字符串与注释一个字符都不动,全部在本页浏览器内完成。

提示:输入框里按 Ctrl + Enter(macOS 用 Cmd + Enter)可直接格式化;单独按 Enter 是换行。

使用方法

  1. 把要排版的 SQL 粘贴到「输入 SQL」框。输入框已预置一段 183 个字符、挤成 1 行的订单统计查询,打开页面即可直接看到效果。
  2. 点「格式化」,或直接在输入框里按 Ctrl + Enter,右侧出现断行缩进后的结果。
  3. 观察输出:SELECT、FROM、WHERE 这类子句关键字各占一行并统一大写,AND、OR 和列清单里的逗号会另起一行并缩进一级。
  4. 如果检测到未闭合的引号或括号数量对不上,下方会用中文说明是哪一类问题,排版结果仍会给出,由你决定是否修正。
  5. 确认后点「复制结果」带走,或点「下载 .sql」保存成 UTF-8 编码的文件。

这个SQL格式化工具能解决什么问题

慢查询日志、ORM 生成的语句和聊天记录里的 SQL 经常挤成一行,几百个字符连在一起,肉眼找 WHERE 条件要靠数括号。这个 SQL 格式化工具主要用在四个场景:一是把整段挤成一行的查询按子句断开,FROM、WHERE、GROUP BY 各占一行,结构一眼可读;二是代码评审前统一风格,把小写的 select、where 统一成大写关键字,避免「风格不一致」这类无意义的评审意见;三是读子查询嵌套的语句时,靠括号深度缩进看清哪一层是主查询、哪一层是派生表;四是写文档或教程时把示例排版成层级分明的样子。

本页只做分词、大写和断行缩进三件事:不连接数据库、不做语法校验、也不执行语句——把 select 写成 se1ect 它照样排版,因为它的职责是排版不是纠错。要把 SQL 查询结果转成别的格式,用页面底部的专门工具更合适。

格式化原理与规则说明

SQL格式化的整个流程分三步:分词 → 大写 → 断行重组。分词器逐字符扫描输入,识别出五类记号:字符串字面量(单引号或双引号包裹,内部两个连续引号按转义处理)、注释(-- 到行尾、/* */ 跨行)、单词、数字、符号。只有单词类记号才参与大写和断行判断,这就是引号保护的来源——'select,from(where)' 在分词阶段就被整体截为一个字符串记号,里面的内容永远不会被当成关键字。

大写依据一张固定词表,共 53 个词,覆盖子句(SELECT、FROM、WHERE 等)、连接(JOIN、LEFT、ON)、条件(AND、OR、NOT、IN、BETWEEN)、聚合函数(COUNT、SUM、AVG、MIN、MAX)等。词表外的词一律保持你写的大小写,所以 ILIKE、TOP 这类方言词不会被误改。词表是固定枚举而不是正则猜测,这是它不会把列名 order 之外的普通标识符改坏的原因——当然,恰好叫 order 的列名也会被大写,这是无词法分析的排版工具的固有边界,见「边界与精度」一节。

断行与缩进用三个量控制:括号深度、断行词表、续行规则。断行词表 20 个(SELECT、FROM、WHERE、GROUP、ORDER、HAVING、LIMIT、OFFSET、UNION、VALUES、SET、JOIN 及五种 JOIN 前缀、INSERT、UPDATE、DELETE),命中就另起一行,缩进等于当前括号深度乘 2 个空格;AND、OR 另起一行时多缩进一级;括号深度为 0 的逗号(列清单)也多缩进一级;每遇到一个左括号,内部的行整体加深一级——子查询就是这样被整体缩进去的。

完整示例(数值仅作演示)

示例条件:输入框预置的那段查询,压缩态 183 个字符、1 行。点「格式化」后输出 200 个字符、11 行,横向只多了 17 个字符(关键字大写带来的),纵向从 1 行变成 11 行:

SELECT u.id,
  u.name,
  COUNT(o.id) AS order_cnt
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.age > 18
  AND u.city = 'beijing'
GROUP BY u.id,
  u.name
ORDER BY order_cnt DESC
LIMIT 10

第二个示例演示子查询缩进:输入 select id from users where status='active' and id in (select user_id from orders where total>100),共 97 个字符 1 行,输出 110 个字符、7 行。左括号之后所有行缩进一级,右括号之后恢复原层级——主查询和派生表的边界一目了然:

SELECT id
FROM users
WHERE status = 'active'
  AND id IN (
  SELECT user_id
  FROM orders
  WHERE total > 100)

两段示例的字符数与行数都是用与本页内联代码同一份算法离线复算的,你打开页面点一次「格式化」应该得到逐字符一致的结果。

关键字词表与断行行为对照表

下表把全部 53 个大写词按行为分成四类,可以直接对照检查输出结果:

类别词数量断行行为
子句关键字SELECT FROM WHERE GROUP ORDER HAVING LIMIT OFFSET UNION VALUES SET11另起一行,缩进 = 括号深度 × 2 空格
JOIN 族JOIN LEFT RIGHT INNER CROSS FULL6同上;但后跟左括号时按函数处理不断行
语句动词INSERT UPDATE DELETE3另起一行;DELETE 后的 FROM 不再断行
续行词AND OR 及深度 0 的逗号2 + 1另起一行并额外缩进一级
其余词表词NOT IN ON AS LIKE BETWEEN COUNT SUM 等31只大写不断行
词表外标识符列名、表名、别名、方言词—大小写原样保留
字符串字面量'beijing'、"id"—整段保护:不大写、不断行、不参与括号计数
注释-- 行注释、/* 块注释 */—逐字符原样保留

输入范围、边界与精度说明

SQL格式化不做语法校验,所以它的边界全在「词法识别」这一层,以下情况你应该提前知道:

常见问题

格式化会改变我的 SQL 吗?

只改两类字符:空白(断行与缩进)和词表内关键字的大小写。字符串字面量、注释、标识符的大小写都原样保留。语义上唯一的例外是那些恰好与关键字同名的未加引号列名,它们会被大写,详见「边界与精度」第一条。

为什么 COUNT、SUM 后面的括号没有空格?

函数调用风格:词表里的聚合函数大写后,左括号紧跟不留空格,写成 COUNT(o.id);而 IN、ON 这类条件词后面保留空格。区分依据是分词时看左括号前一个词是否属于条件类词表,这样函数与条件的视觉差异与多数 IDE 一致。

支持 MySQL、PostgreSQL、SQL Server 的方言吗?

词表是三家通用部分的固定枚举。方言特有词(如 PostgreSQL 的 ILIKE、SQL Server 的 TOP)不在断行表里,会按普通标识符原样保留大小写并正常参与断行,不会被改写也不会报错。

字符串里的 select 为什么没有变大写?

分词器先于大写步骤运行,引号包裹的内容在扫描阶段就被整体截为一个字符串记号,后续步骤根本看不到它内部。'select,from(where)' 这种把整个语法塞进字符串的极端写法也能原样保留,这是引号保护机制的设计目标。

几千行的存储过程能处理吗?

100 KB 以内会随输入实时排版;超过 100 KB 需要点一次「格式化」按钮;1 MB 以上拒绝。存储过程源码通常远小于 100 KB,一般不会触及阈值。体积过大时建议按语句拆段处理。

提示「未闭合的字符串」是什么意思?

扫描到行尾也没找到与开头配对的引号。常见原因是字符串里真的含有一个未转义的单引号——SQL 里的转义写法是把引号连写两次,例如 'it''s'。修正引号配对后提示自动消失。

结果和我 IDE 里的排版不一样?

排版风格本就多家并存:本页采用「子句顶格对齐、AND 与逗号缩进一级、函数括号紧跟」的风格,等价于多数数据库课程的书写规范。IDE 里常见的列右对齐、CASE 树状展开属于表达式级排版,本页不做。

会把我公司的查询语句上传吗?

不会。分词和重组全部在本页的 JavaScript 里完成,没有网络请求,你可以在开发者工具的 Network 面板里核实——点「格式化」前后不会出现任何新请求。

相关工具