PostgreSQL SQL 格式化工具

粘贴一段 Postgres 查询,得到整洁、缩进一致的 SQL。预处理语句中的编号占位符 $1 会被识别出来供你填值,JSONB 运算符、类型转换和美元引用的函数体等 Postgres 特有语法也会被保留。

一条 PostgreSQL 查询,格式化前后对比

下面这条未格式化的查询就是上方编辑器里加载的示例,输出则是本工具在默认选项下返回的原始结果,没有任何手工修饰。

粘贴进来的内容
WITH recent AS (SELECT user_id, count(*) AS n, max(created_at) AS last_seen FROM events WHERE created_at >= $1 AND payload->>'type' = $2 GROUP BY user_id) SELECT u.id, u.email, r.n, row_number() OVER (ORDER BY r.n DESC) AS rank FROM users u JOIN recent r ON r.user_id = u.id WHERE u.status = 'active' AND u.created_at::date BETWEEN $3 AND $4 ORDER BY r.n DESC LIMIT 50
格式化后的输出
WITH
  recent AS (
    SELECT
      user_id,
      count(*) AS n,
      max(created_at) AS last_seen
    FROM
      events
    WHERE
      created_at >= $1
      AND payload ->> 'type' = $2
    GROUP BY
      user_id
  )
SELECT
  u.id,
  u.email,
  r.n,
  row_number() OVER (
    ORDER BY
      r.n DESC
  ) AS rank
FROM
  users u
  JOIN recent r ON r.user_id = u.id
WHERE
  u.status = 'active'
  AND u.created_at::date BETWEEN $3 AND $4
ORDER BY
  r.n DESC
LIMIT
  50

它能处理的 PostgreSQL 语法

通用格式化工具往往会破坏方言特有的语法,或者干脆拒绝处理。以下是本工具针对 PostgreSQL 做过测试的语法结构。

$1, $2

预处理语句中的编号占位符会被识别出来,可以填值生成一条可执行的查询。

payload->>'key'

JSON 和 JSONB 运算符会原样保留。

value::type

类型转换语法绝不会被误当成 :name 参数。

$$ ... $$

美元引用的函数体被视为字面量,因此其中的关键字不会被重新格式化。

WITH ... AS

每个 CTE 的 WHERE 子句都会单独列出,可以独立编辑。

OVER (PARTITION BY ...)

窗口函数及其窗口帧会被格式化,而不会把子句拆散。

PostgreSQL 格式化工具常见问题

它支持预处理语句中的 $1 占位符吗?

支持。Postgres 的编号占位符会被检测出来并列在参数面板中。逐个填好值,再把输出切换为填值 SQL,就能得到一条可以直接粘进 psql 的查询。

它会破坏我的 ::类型转换或 JSONB 运算符吗?

不会。类型转换与 :name 参数被区分开来,-> 和 ->> 等 JSON/JSONB 运算符会原样通过。

能格式化包含多个 CTE 的查询,并且只编辑其中一个吗?

可以。每个 WHERE 子句都会按所属的 CTE 分别列出,所以由一串 WITH 块组成的查询会为每个块给出一个条目。选中一个,用 AND/OR 树或节点图编辑,改动只会写回那一个子句,查询的其余部分逐字节保持不变。

能格式化不完整的查询,或者单独一段 WHERE 吗?

可以。这里没有任何环节依赖完整有效的解析,所以你可以粘贴从日志行或 ORM 调试输出里抠出来的片段——哪怕只有 WHERE created_at >= $1 AND status = $2——它照样会被格式化,并且可以可视化编辑。

美元引用中的 PL/pgSQL 函数体会保持原样吗?

会。美元引用的函数体被当作单个字面量处理,里面的关键字不会被当成外层语句的一部分重新缩进;开始标记只与自己的结束标记配对,而不是碰到的下一个美元符号。

能把 Postgres 查询压缩回一行吗?

能,美化和压缩都提供。压缩会按真实空白处理,而不是套一个笼统的正则表达式,因此字符串字面量内部的空格得以保留,压缩后的查询返回的行与原来完全一致。