如何用Python精准重命名SQL语句中的表与列(含同名场景)
批量重命名SQL表名:解决表列同名混淆问题
问题背景
需要批量修改多条SQL查询中的指定表名,但遇到以下场景时现有方案失效:
- 表名与列名同名(如
select money from money),正则会误把列名也替换,导致结果不符合预期 - 同名列存在于不同表中时,批量替换会误改非目标表的列名
之前尝试过的方案均有缺陷:
- 正则表达式无法覆盖所有边缘场景,无法区分表名和列名的上下文
- 使用sqlparse、sqlglot库能识别表名,但不知道如何精准修改表名节点,避免影响列名
现有代码问题示例
用正则实现的替换函数会同时修改表名和列名:
import re def rename_tables(sql, table_names_map): for old_table_name, new_table_name in table_names_map.items(): sql = re.sub(r'\b' + re.escape(old_table_name) + r'\b', new_table_name, sql, flags=re.I) return sql if __name__ == '__main__': sql_two = "select money from money" rename_dict_two = {'money':'rubber'} print(rename_tables(sql_two, rename_dict_two))
执行结果:
select rubber from rubber
期望结果:
select money from rubber
可靠解决方案:基于SQLGlot的AST精准修改
SQLGlot可以将SQL解析为抽象语法树(AST),通过遍历并修改表名节点,实现只替换表名、不影响列名的效果。以下是具体实现:
import sqlglot def rename_tables_sqlglot(sql, table_names_map): # 解析SQL为AST parsed = sqlglot.parse_one(sql) # 遍历所有表引用节点 for node in parsed.find_all(sqlglot.exp.Table): table_name = node.name.lower() # 匹配需要替换的表名(不区分大小写) for old_name, new_name in table_names_map.items(): if old_name.lower() == table_name: node.set("name", new_name) break # 生成修改后的SQL return parsed.sql(dialect=None) if __name__ == '__main__': # 测试场景1:表列同名 sql_two = "select money from money" rename_dict_two = {'money':'rubber'} print(rename_tables_sqlglot(sql_two, rename_dict_two)) # 测试场景2:嵌套子查询 sql_one = "select K.a,K.b from (select H.b from (select G.c from (select F.d from (select E.e from A, B, C, D, E), F), G), H), I, J, K order by 1,2; " rename_dict_one = {'A': 'table1', 'B': 'table2', 'C': 'table3', 'D': 'table4', 'E': 'table5', 'F': 'table6', 'G': 'table7', 'H': 'table8', 'I': 'table9', 'J': 'table10', 'K': 'table11'} print(rename_tables_sqlglot(sql_one, rename_dict_one))
验证结果
执行上述代码后:
- 表列同名场景输出:
SELECT money FROM rubber
- 嵌套子查询场景输出:
SELECT K.a, K.b FROM (SELECT H.b FROM (SELECT G.c FROM (SELECT F.d FROM (SELECT E.e FROM table1, table2, table3, table4, table5), table6), table7), table8), table9, table10, table11 ORDER BY 1, 2;
完全符合预期,仅修改表名,列名和嵌套子查询中的表引用均被正确处理。
内容的提问来源于stack exchange,提问作者TM3000
相关产品推荐
相关产品推荐

