如何使用 SQLFluff 解析并提取嵌套 SELECT 查询中的内外层语句

千丽同学_8905

千丽同学_8905

2026-07-15

241人浏览

原创

如何使用 SQLFluff 解析并提取嵌套 SELECT 查询中的内外层语句

本文介绍如何利用 sqlfluff 的解析能力精准识别、分离并重构嵌套 select 语句,将内层查询提取为 ctas(create table as)语句,外层查询改写为对新表的引用,适用于复杂 sql 的自动化重构场景。

本文介绍如何利用 sqlfluff 的解析能力精准识别、分离并重构嵌套 select 语句,将内层查询提取为 ctas(create table as)语句,外层查询改写为对新表的引用,适用于复杂 sql 的自动化重构场景。

SQLFluff 不仅是 SQL 格式化与校验工具,其底层解析器还提供了强大的 AST(抽象语法树)遍历能力,可精确识别嵌套结构。对于形如 SELECT * FROM (SELECT a, b FROM agents) 的查询,目标是将内层 SELECT a, b FROM agents 提取为独立的 CTAS 语句,并将外层 SELECT * FROM (...) 替换为 SELECT * FROM reagents。

✅ 正确获取嵌套 SELECT 节点

推荐使用 Linter.parse_string()(而非低层 Parser),因其自动完成词法分析、语法解析与段落归类,返回结构更完整、语义更清晰的 ParsedString 对象:

from sqlfluff.core import Linter

sql = "SELECT * FROM (SELECT a, b FROM agents)"
linter = Linter(dialect="ansi")
parsed = linter.parse_string(sql)

# 递归查找所有 select_statement 类型节点(按嵌套深度从外到内)
selects = list(parsed.tree.recursive_crawl("select_statement"))
print(f"共找到 {len(selects)} 个 SELECT 语句")
# 输出:
# 共找到 2 个 SELECT 语句
# selects[0].raw → "SELECT * FROM (SELECT a, b FROM agents)"
# selects[1].raw → "SELECT a, b FROM agents"

注意:recursive_crawl("select_statement") 返回的是按文档顺序(非深度优先)遍历的节点列表,最外层 SELECT 总在索引 0,最内层(无嵌套子查询的)通常在末尾——这对提取“最深层可提取子查询”非常关键。

天壤小白
天壤小白

天壤小白是一款AI开发辅助工具,一站式AI应用开发平台。

下载

?️ 构建 CTAS 并重写外层引用

SQLFluff 的 BaseSegment 对象不直接支持“生成修改后 SQL”,但可通过其 pos_marker 定位原始文本位置,结合字符串切片或 sqlfluff.templater.StringTemplate 实现安全替换。更稳健的做法是:提取内层 SELECT 的完整文本,构造 CTAS;再用正则或 AST 替换外层中的子查询括号部分

以下为生产就绪的重构示例(含错误防护):

import re
from sqlfluff.core import Linter

def extract_and_rewrite_ctas(sql: str, temp_table_name: str = "reagents") -> tuple[str, str]:
    linter = Linter(dialect="ansi")
    parsed = linter.parse_string(sql)

    # 获取所有 SELECT 节点
    selects = list(parsed.tree.recursive_crawl("select_statement"))
    if len(selects) <h3>⚠️ 注意事项与进阶建议</h3>
  • 括号匹配风险:正则替换 (SELECT ...) 在多层嵌套或含字符串字面量(如 '(')时易出错。强烈建议基于 pos_marker 做字节级替换,或使用 sqlfluff.core.parser.segments.BaseSegment.edit()(需深入理解 segment tree)。
  • Dialect 兼容性:dialect="ansi" 支持基础语法;若涉及窗口函数、CTE 或方言特性(如 BigQuery 的 QUALIFY),请指定对应 dialect(如 "bigquery")。
  • 性能考量:recursive_crawl() 是 O(n) 操作,对超长 SQL(>10k 行)建议先做预过滤。
  • 扩展性设计:可封装为 SQLRewriter 类,支持链式调用(.extract_subquery().as_ctas("tbl").replace_in_parent()),便于集成 CI/CD 流程。

通过 SQLFluff 的结构化解析能力,你不再依赖脆弱的正则表达式——而是基于真实语法树进行语义感知的重构,这正是处理企业级复杂 SQL 自动化改造的核心优势。

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1551

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

3704

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1569

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

21217

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2607

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2667

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1083

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

576

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2063

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.1万人学习