如何用Python sqlparse调整子查询格式并进阶为该工具专家?
关于sqlparse格式化SQL及进阶建议
一、调整子查询括号换行格式
当前你使用的sqlparse格式化代码为:
print(sqlparse.format(first, reindent=True, keyword_case='upper', ofrmt='python', wrap_after=8, indent_after_first=True))
默认参数无法直接实现子查询左括号后换行、右括号前换行的效果,且保留count(1)的格式。可以通过解析SQL的语法树,自定义处理括号位置来实现:
实现代码示例
import sqlparse from sqlparse.sql import Parenthesis from sqlparse.tokens import Newline def format_subquery_parentheses(sql): parsed = sqlparse.parse(sql)[0] def traverse(token): if isinstance(token, Parenthesis): # 识别子查询括号(内部包含SELECT语句) inner_tokens = [t for t in token.tokens if not t.is_whitespace and t.value not in '()'] if inner_tokens and inner_tokens[0].value.upper() == 'SELECT': # 在左括号后插入换行 token.tokens.insert(1, sqlparse.sql.Token(Newline, '\n')) # 在右括号前插入换行 for idx, t in enumerate(token.tokens): if t.value == ')': token.tokens.insert(idx, sqlparse.sql.Token(Newline, '\n')) break # 递归处理所有子节点 if hasattr(token, 'tokens'): for t in token.tokens: traverse(t) traverse(parsed) # 应用基础格式化并修正多余空格 formatted = sqlparse.format(str(parsed), reindent=True, keyword_case='upper', wrap_after=8, indent_after_first=True) formatted = formatted.replace('(\n ', '(\n').replace(' \n)', '\n)') return formatted # 测试调用 first = """SELECT dt, count(1) FROM (SELECT dt, WEEK FROM fin_dim.dim_m_y23_sixth_weekday_jwm_a) GROUP BY 1;""" print(format_subquery_parentheses(first))
这段代码会遍历SQL语法树,精准识别子查询的括号,在指定位置插入换行,同时不会影响count(1)这类函数的括号格式。
二、成为sqlparse专家的建议
- 吃透核心机制:深入研究sqlparse的token解析逻辑,熟悉
Token、ParseTree、Parenthesis等核心类的结构,理解SQL如何被拆解为不同类型的token单元。 - 多场景实战测试:针对复杂嵌套查询、存储过程、不同SQL方言(MySQL、PostgreSQL等)做格式化测试,记录不同参数组合的效果,积累处理边界情况的经验。
- 自定义扩展规则:学习编写个性化的格式化/解析规则,比如针对特定业务语法的特殊处理,通过修改token遍历逻辑实现定制化需求。
- 跟进社区动态:关注官方的问题讨论和版本更新,了解新功能迭代,学习其他开发者的问题解决方案。
- 阅读源码案例:查看sqlparse源码中的测试用例和内置格式化逻辑,学习官方处理各类SQL结构的思路,必要时可直接参考源码修改或扩展功能。
内容的提问来源于stack exchange,提问作者X.Kevin
相关产品推荐
相关产品推荐

