sqlglot提取Where子句列(含嵌套SQL)报Unexpected token错误解决
问题根因
你遇到的解析报错、提取不全问题来自两个核心原因:
- 你的SQL包含
{{location}}这类模板占位符、$$包裹的动态拼接标记,不属于标准SQL语法,sqlglot默认词法规则无法识别,直接抛出Invalid expression / Unexpected token错误 - 原有逻辑仅获取了最外层SELECT语句的Where节点,没有递归遍历多层嵌套子查询、派生表内部的Where节点,只能拿到最外层过滤条件的列
可行实现方案
步骤1:预处理特殊字符
先把SQL中sqlglot无法识别的非标准语法片段替换为合法SQL结构,不会破坏原有的列引用关系:
- 直接删除所有
$$动态拼接标记 - 将所有
{{变量名}}格式的模板占位符替换为SQL通用参数占位符?
步骤2:递归遍历所有Where节点
解析SQL生成抽象语法树(AST)后,遍历整棵树找到所有层级的Where节点,提取每个节点下引用的所有列名,自动去重。
可直接运行的代码
import re import sqlglot import sqlglot.expressions as exp def extract_where_columns(sql: str, include_table_alias: bool = False) -> set: """ 提取SQL中所有层级Where子句引用的列名 :param sql: 待解析的原始SQL :param include_table_alias: 结果是否保留表别名前缀(如dc.id),默认False仅返回列名 """ # 预处理非标准SQL片段 processed_sql = sql.replace("$$", "") # 移除动态拼接标记 processed_sql = re.sub(r"\{\{.*?\}\}", "?", processed_sql) # 模板占位符替换为合法参数? # 指定MySQL方言解析,适配IF函数等MySQL专属语法,避免方言兼容错误 ast = sqlglot.parse_one(processed_sql, dialect="mysql") columns = set() # 遍历AST中所有Where节点,覆盖所有嵌套子查询/派生表/IN子查询的Where条件 for where_node in ast.find_all(exp.Where): for col in where_node.find_all(exp.Column): if include_table_alias: col_name = col.sql(dialect="mysql") else: col_name = col.name columns.add(col_name) return columns # 简单示例测试 test_simple_sql = """select column_3, column_4 from table_name where column_1 = 10 and column_2="test" """ print("简单SQL提取结果:", extract_where_columns(test_simple_sql)) # 输出: {'column_1', 'column_2'} # 替换为你自己的长SQL即可运行 # sql_query = "你的长SQL内容" # print("复杂SQL提取结果:", extract_where_columns(sql_query))
注意事项
- 如果需要提取JOIN关联条件ON里的引用列,只需要在遍历节点时新增判断
exp.On类型即可,逻辑完全一致 - 提取逻辑自动覆盖所有查询层级:最外层查询、子查询、派生表、IN语句内嵌套SELECT的Where条件都会被遍历,不会漏提
- 如果你的SQL是其他数据库方言(比如PostgreSQL、SparkSQL),把代码里的
dialect="mysql"换成对应方言名即可
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

