引用说明作者:Sonia Valeja原文链接:https://www.percona.com/blog/streamline-the-sql-code-guide-to-pgformatter/
什么是 pgFormatter
pgFormatter 是一款开源的 SQL 代码格式化工具,将 SQL 代码转换为格式规范、缩进对齐的标准代码。它提升代码可读性,强化 SQL 最佳实践和编码规范,让开发人员专注于业务逻辑而非格式调整。
核心功能
代码美化:将复杂、无格式的 SQL 转换为结构清晰的语句 缩进对齐:确保关键字、子句和表达式的一致性缩进,形成清晰的层次结构 标准风格:遵循标准 SQL 风格指南,保持项目和团队代码一致性 可配置规则:支持自定义格式化规则,适配特定项目需求
安装配置
系统更新
# RedHat/CentOSdnf update# Debian/Ubuntusudo apt-get update
安装依赖
# RedHat/CentOSdnf install perl-CGI# Debian/Ubuntuapt-get install libcgi-pm-perl
安装 pgFormatter
sudo apt-get install pgFormatter
基础用法
# 输出到终端pg_format query.sql# 输出到文件pg_format -o result.sql query.sql# 直接覆盖原文件(谨慎使用)pg_format -i query.sql# 从标准输入读取cat query.sql | pg_format -
核心参数
大小写控制
# 关键字:0=不变, 1=小写, 2=大写(默认), 3=首字母大写pg_format -u 1 query.sql # SELECT -> select# 函数名:0=不变(默认), 1=小写, 2=大写, 3=首字母大写pg_format -f 1 query.sql # COUNT() -> count()# 数据类型:0=不变, 1=小写(默认), 2=大写, 3=首字母大写pg_format -U 2 query.sql # varchar -> VARCHAR
缩进与格式
# 缩进空格数(默认 4)pg_format -s 2 query.sql# 使用制表符pg_format -T query.sql# 逗号在开头(默认在末尾)pg_format -b query.sql# INSERT 语句每个逗号后换行pg_format -B insert.sql
内容处理
# 移除注释pg_format -n query.sql# 保留 PL/pgSQL 中的空行pg_format -k query.sql# 匿名化字面量(隐藏敏感数据)pg_format -a query.sql# 为语句添加编号注释pg_format -N query.sql
组合使用
# 关键字大写 + 函数小写 + 2空格缩进pg_format -u 2 -f 1 -s 2 -o output.sql input.sql
实战案例
案例 1:基础 SQL 格式化
格式化前:
SELECT c.customer_id, c.first_name, c.last_name, COUNT(o.order_id) AS total_ordersFROM customers c JOIN orders o ON c.customer_id = o.customer_idWHERE c.country IN ('USA', 'Canada','India', 'UK')AND o.order_date BETWEEN'2023-01-01'AND'2023-05-31'GROUPBY c.customer_id, c.first_name, c.last_nameHAVINGCOUNT(o.order_id) > 5ORDERBY total_orders DESC, c.last_name ASC;
执行命令:
pg_format query.sql
格式化后:
SELECT c.customer_id, c.first_name, c.last_name,COUNT(o.order_id) AS total_ordersFROM customers cJOIN orders o ON c.customer_id = o.customer_idWHERE c.country IN ('USA', 'Canada', 'India', 'UK')AND o.order_date BETWEEN'2023-01-01'AND'2023-05-31'GROUPBY c.customer_id, c.first_name, c.last_nameHAVINGCOUNT(o.order_id) > 5ORDERBY total_orders DESC, c.last_name ASC;
案例 2:PL/pgSQL 函数格式化
格式化前:
CREATEORREPLACEFUNCTION calculate_bonus(emp_id INT, base_salary NUMERIC)RETURNSNUMERICAS $$DECLARE bonus_rate NUMERIC;total_bonus NUMERIC;BEGINSELECTCASEWHEN salary>100000THEN0.15WHEN salary>50000THEN0.10ELSE0.05ENDINTO bonus_rate FROM employees WHERE employee_id=emp_id;total_bonus:=base_salary*bonus_rate;RETURN total_bonus;END;$$ LANGUAGE plpgsql;
执行命令:
pg_format -f 1 -k function.sql
格式化后:
CREATEORREPLACEFUNCTION calculate_bonus ( emp_id INT, base_salary NUMERIC)RETURNSNUMERICAS $$DECLARE bonus_rate NUMERIC; total_bonus NUMERIC;BEGINSELECTCASEWHEN salary > 100000THEN0.15WHEN salary > 50000THEN0.10ELSE0.05ENDINTO bonus_rateFROM employeesWHERE employee_id = emp_id; total_bonus := base_salary * bonus_rate; RETURN total_bonus;END;$$LANGUAGE plpgsql;
案例 3:多语句文件格式化
格式化前:
-- 创建表CREATETABLE products(idSERIAL PRIMARY KEY,nameVARCHAR(100) NOTNULL,price NUMERIC(10,2));-- 插入数据INSERTINTO products(name,price) VALUES('Laptop',999.99),('Mouse',29.99),('Keyboard',79.99);-- 查询数据SELECT p.name,p.price,CASEWHEN p.price>500THEN'Premium'ELSE'Standard'ENDascategoryFROM products p WHERE p.price>20ORDERBY p.price DESC;
执行命令:
pg_format multi.sql
格式化后:
-- 创建表CREATETABLE products (idSERIAL PRIMARY KEY,nameVARCHAR(100) NOTNULL, price NUMERIC(10, 2));-- 插入数据INSERTINTO products (name, price)VALUES ('Laptop', 999.99), ('Mouse', 29.99), ('Keyboard', 79.99);-- 查询数据SELECT p.name, p.price,CASEWHEN p.price > 500THEN'Premium'ELSE'Standard'ENDAScategoryFROM products pWHERE p.price > 20ORDERBY p.price DESC;
案例 4:INSERT 语句换行优化
格式化前:
INSERTINTO orders(order_id,customer_id,product_id,quantity,price) VALUES(1001,501,2001,5,29.99),(1002,502,2002,3,149.99),(1003,503,2003,1,999.99);
执行命令:
pg_format -B insert.sql
格式化后:
INSERTINTO orders (order_id, customer_id, product_id, quantity, price)VALUES (1001,501,2001,5,29.99), (1002,502,2002,3,149.99), (1003,503,2003,1,999.99);
案例 5:敏感数据匿名化
原始查询:
SELECT * FROMusersWHERE email='john@example.com'AND salary=85000;
执行命令:
pg_format -a sensitive.sql
匿名化后:
SELECT *FROMusersWHERE email = 'xxxxx'AND salary = xxx;
案例 6:事务脚本格式化
格式化前:
BEGIN;SETTRANSACTIONISOLATIONLEVELSERIALIZABLE;CREATETABLE audit_log(id BIGSERIAL PRIMARY KEY,actionVARCHAR(50),timestampTIMESTAMPDEFAULTCURRENT_TIMESTAMP);INSERTINTO audit_log(action) SELECT'CREATE';COMMIT;
执行命令:
pg_format transaction.sql
格式化后:
BEGIN;SETTRANSACTIONISOLATIONLEVELSERIALIZABLE;CREATETABLE audit_log (id BIGSERIAL PRIMARY KEY,actionVARCHAR(50),TIMESTAMPTIMESTAMPDEFAULTCURRENT_TIMESTAMP);INSERTINTO audit_log (action)SELECT'CREATE';COMMIT;
配置文件使用
在项目根目录或用户目录创建 .pg_format 文件:
# 缩进 2 个空格spaces = 2# 关键字大写keyword-case = 2# 函数名小写function-case = 1# 数据类型小写type-case = 1# 保留空行keep-newline = 1
pgFormatter 会自动读取配置文件,也可通过 -c 指定:
pg_format -c /path/to/config query.sql# 忽略配置文件pg_format -X query.sql
批量处理
# 格式化当前目录所有 SQL 文件for file in *.sql; do pg_format -i "$file"done# 递归格式化子目录find ./sql -name "*.sql" -exec pg_format -i {} \;
Web 界面
在线工具:https://sqlformat.darold.net/
使用步骤:
安全提示:避免在 Web 界面处理包含敏感数据的查询。
应用场景
调试与故障排查
格式化代码使开发人员更容易定位潜在问题,快速理解查询逻辑。
代码审查
提交前格式化代码,让审查者专注于逻辑正确性而非格式问题。
查询优化
清晰的缩进和对齐帮助识别性能瓶颈,便于优化查询结构。
数据库迁移
确保迁移脚本格式一致,降低部署过程中的错误风险。
团队协作
统一的代码风格促进团队协作,减少代码冲突和理解成本。
编码标准
通过配置文件确保代码库遵循组织的编码规范。
常见问题
Q:格式化结果不符合预期?
# 尝试不同格式类型pg_format -t query.sql# 或忽略配置文件pg_format -X query.sql
Q:如何处理动态 SQL?
# 使用自定义分隔符pg_format -S "$$" dynamic.sql
Q:格式化时报错?
# 启用调试模式pg_format -d query.sql
Q:如何保护特定代码不被格式化?
# 使用占位符正则表达式pg_format -p '/\*NOFORMAT\*/.*?/\*END\*/' query.sql
参考资源
- 官方下载:http://sourceforge.net/projects/pgformatter/
- GitHub 仓库:https://github.com/darold/pgFormatter
- 在线工具:https://sqlformat.darold.net/
总结
pgFormatter 是提升 PostgreSQL 代码质量的实用工具。通过将其集成到开发流程中,可获得格式一致、可读性强的 SQL 代码,提高生产力并降低错误风险。无论是处理复杂查询还是维护大型代码库,pgFormatter 都是提升代码质量的有力工具。
环境适配说明
本文的安装步骤、命令示例和功能特性基于特定版本的 pgFormatter。实际使用时请注意:
- 版本差异:不同版本功能可能有差异,建议查阅官方文档确认支持的功能
- 系统兼容:不同 Linux 发行版的包管理器和依赖项可能不同,需根据实际系统调整
- 测试验证:生产环境使用前,先在测试环境验证格式化效果
- 数据安全:处理生产数据时注意脱敏,避免在公共环境暴露敏感信息
建议在正式使用前充分测试,确保符合项目的开发规范和安全要求。