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