实用SQL代码解析工具——sqlparse
1 引言
一个数据分析团队往往会积累大量基于SQL的代码,用于日常的报表,模型数据提取,业务决策等等。有时随着公司的发展和技术更替,公司的数据仓库会进行迁移或重构,当表结构,字段名或者表名发生变化时,包含这些表的SQL代码就需要相应地进行改写。人为改写一段段业务代码,尤其是对字段或者表名的修改,往往比较重复而且容易遗漏。
懒惰是程序员的第一生产力,既然是重复的工作,那么有没有什么工具可以帮助我们自动化这一过程呢?
2 sqlparse开源库
2.1 介绍
想要改写SQL代码,关键的一步是对SQL进行解析。sqlparse是基于Python的一个无验证解析器,他提供了一个简单的parse()函数来返回类似语法树的解析结构。我们用_pprint_tree()函数打印下解析后的SQL语句:
import sqlparse
query = 'Select a, col_2 as b from Table_A;'
sqlparse.parse(query)[0]._pprint_tree()
输出为:
|- 0 DML 'Select'
|- 1 Whitespace ' '
|- 2 IdentifierList 'col_1,...'
| |- 0 Identifier 'col_1'
| | `- 0 Name 'col_1'
| |- 1 Punctuation ','
| |- 2 Whitespace ' '
| `- 3 Identifier 'col_2 ...'
| |- 0 Name 'col_2'
| |- 1 Whitespace ' '
| |- 2 Keyword 'as'
| |- 3 Whitespace ' '
| `- 4 Identifier 'b'
| `- 0 Name 'b'
|- 3 Whitespace ' '
|- 4 Keyword 'from'
|- 5 Whitespace ' '
|- 6 Identifier 'Table_A'
| `- 0 Name 'Table_A'
`- 7 Punctuation ';'
可以看到sqlparse可以准确的识别出查询语句中的关键词,并且字段,表名被识别成了Identifier类型。结合前后token中的关键词就可以进一步判断出具体是字段还是表名。在此之前还需要了解各种类型包含的各种方法。
2.2 类型定义
sqlparse的基础类型是Token,其中ttype和value两个常用属性。此外类似树结构的节点,他可以通过parent属性关联上一层token。它的常用方法主要是对该token属性的访问和判断:
class sqlparse.sql.Token(ttype, value):
flatten(): Resolve subgroups.
has_ancestor(other): Returns True if other is in this tokens ancestry.
is_child_of(other): Returns True if this token is a direct child of other.
match(ttype, values, regex=False): checks whether the token matches the given arguments.
within(group_cls): Returns True if this token is within group_cls.
TokenList是Token类型的继承,定义为一群token的集合。通过token.tokens属性来访问。如例子中的'col_2 as b'就被判定为了Identifier类型的TokenLis他。除了继承和部分覆写了Token类型的方法以外,它还定义了获取子token位置,名称,匹配搜索子token等方法:
class sqlparse.sql.TokenList(tokens=None):
flatten(): Generator yielding ungrouped tokens. This method is recursively called for all child tokens. (覆写了flatten方法)
get_alias(): Returns the alias for this identifier or None.
get_name(): Returns the name of this identifier.
group_tokens(grp_cls, start, end, include_end=True, extend=False): Replace tokens by an instance of grp_cls.
has_alias(): Returns True if an alias is present.
token_first(skip_ws=True, skip_cm=False): Returns the first child token.
token_index(token, start=0): Return list index of token.
token_prev(idx, skip_ws=True, skip_cm=False): Returns the previous token relative to idx.*
2.3 词法解析
对于SQL中的DDL(Data Definition Language,数据定义语言)/DML(Data Manipulation Language,数据操纵语言)等关键词,sqlparse主要通过正则表达式识别,所有的正则表达与token类型的对应关系储存在keywords.py里的SQL_REGEX变量中,必要时可以修改正则表达来适应不同的数据仓库语法和函数。
3 案例:从查询中提取表名
sqlparse作者在源码中提供了提取表名的范例,主要思路是在解析过程中遇到关键词from或者join后,提取其后的tokenList。
ALL_JOIN_TYPE = ('LEFT JOIN', 'RIGHT JOIN', 'INNER JOIN', 'FULL JOIN', 'LEFT OUTER JOIN', 'FULL OUTER JOIN')def is_subselect(parsed):"""是否子查询:param parsed: T.Token"""if not parsed.is_group:return Falsefor item in parsed.tokens:if item.ttype is DML and item.value.upper() == 'SELECT':return Truereturn Falsedef extract_from_part(parsed):"""提取from之后模块"""from_seen = Falsefor item in parsed.tokens:if from_seen:if is_subselect(item):for x in extract_from_part(item):yield xelif item.ttype is Keyword:from_seen = Falsecontinueelse:yield itemelif item.ttype is Keyword and item.value.upper() == 'FROM':from_seen = Truedef extract_join_part(parsed):"""提取join之后模块"""flag = Falsefor item in parsed.tokens:if flag:if item.ttype is Keyword:flag = Falsecontinueelse:yield itemif item.ttype is Keyword and item.value.upper() in ALL_JOIN_TYPE:flag = Truedef extract_table_identifiers(token_stream):for item in token_stream:if isinstance(item, IdentifierList):for identifier in item.get_identifiers():yield identifier.get_name()elif isinstance(item, Identifier):yield item.get_name()elif item.ttype is Keyword:yield item.valuedef extract_tables(sql):"""提取sql中的表名(select语句)"""from_stream = extract_from_part(sqlparse.parse(sql)[0])join_stream = extract_join_part(sqlparse.parse(sql)[0])return list(extract_table_identifiers(from_stream)) + list(extract_table_identifiers(join_stream))
4 总结
sqlparse是一个比较强大的基于python语言的SQL解析工具,开源库在GitHub上获得了2.6k个星星和522次Fork。其代码简洁高效,结构清晰,值得感兴趣的同学细细阅读。
实用SQL代码解析工具——sqlparse相关推荐
- 开源 sql 代码提示工具_有关如何计划开源活动的提示
开源 sql 代码提示工具 在今年的OSCON上 ,Kara Sowles和Francesca Krihely就如何计划和举办技术活动举办了精彩的研讨会. 我参加过的许多技术活动看起来都是完全无缝的, ...
- 推荐两个实用的视频解析工具
01 BTNULL BTNULL是一个视频解析网站,为我们提供了方便快捷的在线视频解析服务.该网站支持解析各种常见的视频网站和平台,我们只需将视频链接粘贴到网站上即可进行解析和观看. BTNULL网站 ...
- 【PC工具】大神级代码注释,漂亮实用的代码注释工具代码logo工具
github上看各路大牛大神的项目代码,经常会看到各种神注释 ...... 那么问题就来了:大神是如何在代码里搞的这些图片代码呢? 打死我也不信是大牛大神一个一个打上去,这不是大牛大神的风格 . 今天 ...
- java 代码解析工具_改善 Java 代码质量的工具与方法
原标题:改善 Java 代码质量的工具与方法 我们可能见过上面的有关代码质量的图片,究竟如何衡量一段代码好坏? 代码质量是什么?为什么它很重要? 作家通过他的著作来讲述了一个清晰的.令人信服的故事.他 ...
- 技术分享 | binlog 实用解析工具 my2sql
作者:赵黎明 爱可生 MySQL DBA 团队成员,Oracle 10g OCM,MySQL 5.7 OCP,擅长数据库性能问题诊断.事务与锁问题的分析等,负责处理客户 MySQL 及我司自研 DMP ...
- 在线Javascript代码加密工具:JJEncode
什么是JJEncode? 就是将JavaScript代码转换成只有符号的字符串编码. 在线JJEncode加密工具:http://www.atoolbox.net/Tool.php?Id=704 温馨 ...
- vscode代码运行时间工具_10款实用的VSCode插件提升你的编辑体验 | 第98期
代码编辑器或者文本编辑器相信大家都不会陌生,但是,常用Windows的朋友大概都知道其自带的"文本编辑器"那是一款多么难用的软件.后来又有一系列的编辑器,比如notepad++.s ...
- /plus/recommend.php sql注入漏洞,DedeCMS 全版本通杀SQL注入漏洞利用代码及工具 -
DedeCMS 全版本通杀SQL注入漏洞利用代码及工具 目前官方最新版已修复该漏洞 V5.7.37 GBK正式版20140228常规更新补丁 http://www.dedecms.com/pl/ ht ...
- php解析命令行参数选项,PHP 命令行参数解析工具类的示例代码
PHP 命令行参数解析工具类的示例代码 /** * 命令行参数解析工具类 * @author guolinchao */ class CommandLine { // 临时记录短选项的选项值 priv ...
- Unity 实用代码 小工具
Unity 实用代码 小工具 Unity 屏幕截图 全屏截图方法 全屏截图方法 带委托事件 自定义截图方法 自定义截图方法 带委托 延迟工具 携程延迟方法 携程延迟带委托方法 场景加载 场景加载 方法 ...
最新文章
- 在Yolov5 Yolov4 Yolov3 TensorRT 实现Implementation
- webbrowser1 脚本报错_c# winform程序 webBrowser 当前页面的脚本发生异常 找不到成员...
- Freemarker静态化ActiveMQ实现
- 操作系统之多线程编程—读者优先/写者优先详解
- mybatis实现分页查询-自己封装分页方法
- 用Python编写博客导出工具
- c++调用gcd函数_c++函数库中一些实用的函数
- Caffe训练时出现了无数个Train net output #.....
- 字符串的最长不重复字串
- 【Kafka】kafka 脚本kafka-configs.sh用法解析
- 网址路由Routing组件如何在mvc中生成网址
- 关于Java里try/catch/finally/有return时执行过程
- 免费45天WPS稻壳会员领取
- 浙江大学14届计算机学院倩倩,胡倩倩(浙江大学副教授)_百度百科
- 对项目需求书撰写的一点理解
- reset清除所有浏览器默认样式
- Python简单词云的制作
- LyX 发布撑持 CJK 的 1.5 正式版
- linux下java导出execl_POI实现导出EXCEL详解
- 信号完整性入门笔记一-细解为什么低频信号在较短传输线不考虑反射?
热门文章
- 神舟IV号开发板-带屏例程源码修改bug(2.8寸屏)
- 微型计算机属于超大规模集成电路计算机,超大规模集成电路计算机是第几代计算机...
- Radius 协议介绍
- c语言数据类型ppt,C语言基本数据类型.ppt
- kali2021安装sougou输入法
- 机械制图与计算机绘图实训报告前言,机械制图论文2000字_机械制图总结以及心得2000字_大一机械制图结课论文...
- php 爬虫图片代码,python爬虫入门教程之糗百图片爬虫代码分享
- 提高 Mac OS X 速度的 52 个方法
- 攻防世界 --> funny_video --> 最完整和正确的解答
- boost::asio 阻塞卡顿问题