警告
本文最后更新于 2021-08-19,文中内容可能已过时。
本章内容仅使用最简单的方法,并且参考了网上教程,适用于自己的项目,仅刚大家参考
SQL解析
简介
sqlparse是一个无验证的SQL解析器。它提供了解析、拆分、格式化SQL语句的能力。
代码:https://github.com/andialbrecht/sqlparse
sqlparse提供了三个基本的函数,用于SQL语句处理。
split
拆分包含多个SQL语句的字符串为SQL语句列表。
语句结尾通过;
分隔。
1
2
3
4
import sqlparse
sql = 'select * from foo; select * from bar;'
sqlparse . split ( sql )
[ u 'select * from foo; ' , u 'select * from bar;' ]
format
format
函数接受关键字参数
keyword_case
关键词upper
、lowersql
的保留字大小写
identifier_case
标识符的upper、lower大小写
strip_comments=Ture
删除注释
reindent=Ture
美化sq缩进语句发生改变
将SQL语句格式化,以便更清晰的展现。
1
2
3
4
5
6
7
8
sql = 'select * from foo where id in (select id from bar);'
print ( sqlparse . format ( sql , reindent = True , keyword_case = 'upper' ))
# 结果
SELECT *
FROM foo
WHERE id IN
( SELECT id
FROM bar );
parse
parse()
返回sql
解析结果tuple
。
tuple
的每个元素对应于split()
的一个SQL语句。
解析的结果也可以通过str()
生成原始的SQL语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sql = 'select * from bar where id=1 limit 1000,2000;'
parsed = sqlparse . parse ( sql )
stmt = parsed [ 0 ]
stmt . tokens
# (<DML 'select' at 0x9b63c34>,
# <Whitespace ' ' at 0x9b63e8c>,
# <Operator '*' at 0x9b63e64>,
# <Whitespace ' ' at 0x9b63c5c>,
# <Keyword 'from' at 0x9b63c84>,
# <Whitespace ' ' at 0x9b63cd4>,
# <Identifier '"somes...' at 0x9b5c62c>,
# <Whitespace ' ' at 0x9b63f04>,
# <Where 'where ...' at 0x9b5caac>)
str ( stmt ) # str(stmt) for Python 3
# 'select * from "someschema"."mytable" where id = 1'
str ( stmt . tokens [ - 1 ]) # or just the WHERE part
# 'where id = 1'
基类
所有返回的对象都从这些基类继承。在Token此类表示单个令牌和 TokenList类是一组令牌。后者提供了检查其子类的方法
Token
1
sqlparse . sql . Token ( ttype , value )
它表示单个标记,并具有两个实例属性:value
标记的未更改值,是标记ttype
的类型。
flatten()
解决分组
has_ancestor(other)
如果其他的再其父类中,则返回
is_child_of(other)
如果标记是其他标记的子标记,则返回
match(ttype, values, regex=False)
within(group_cls)
1
2
3
4
5
6
sql = 'select * from "someschema"."mytable" where id = 1'
parsed = sqlparse . parse ( sql )
stmt = parsed [ 0 ] . tokens
for token in stmt :
print ( token . ttype , token . value )
返回结果如下
Token.Keyword.DML select
Token.Text.Whitespace
Token.Wildcard *
Token.Text.Whitespace
Token.Keyword from
Token.Text.Whitespace
None "someschema"."mytable"
Token.Text.Whitespace
None where id = 1
Token子类类型
sqlparse.sql.Token
sqlparse.sql.Where
sqlparse.sql.Identifier
sqlparse.sql.IdentifierList
token.ttype属性(sqlparse.sql.Token)
Token.Keyword.DDL
标记语法create语句
Token.Keyword.DML
SELECT标记法 select、updata、delete
Token.Keyword SQL
保留的关键字
Token.Text.Whitespace
空格,sql语句间的空格
Token.Text.Whitespace.Newline
sql新的一行间空格
Token.Punctuation
结束标点通常为;
TokenList
一组令牌,t其有一个额外的属性tokens,包含子标记列表
1
2
3
4
5
6
7
8
9
10
11
12
13
flatten ()
get_alias ()
get_name ()
get_parent_name ()
get_token_at_offset ( offset )
group_tokens ( grp_cls , start , end , include_end = True , extend = False )
has_alias ()
insert_after ( where , token , skip_ws = True )
insert_before ( where , token )
token_first ( skip_ws = True , skip_cm = False )
token_index ( token , start = 0 )
token_next ( idx , skip_ws = True , skip_cm = False , _reverse = False )
token_prev ( idx , skip_ws = True , skip_cm = False )
SQL表示类(SQL语句的不同部分)
判断sql的类型DML
/DDL
1
sqlparse . sql . Statement ( tokens = None )
get_type()
语句的类型
1
2
sql = sqlparse . sql . Statement ( stmt )
print ( sql . get_type ())
返回SQL标记关键字SELECT
、select
、updata
、delete
、create
Identifier
标识符
1
sqlparse . sql . Identifier ( tokens = None )
get_array_indices()
返回索引标记列表的迭代器
get_ordering()
返回排序或None大写字符串
get_typecast
None以字符串形式返回类型转换或此对象
is_wildcard
True如果此标识符包含通配符,则返回
IdentifierList
标识符列表
1
sqlparse . sql . IdentifierList ( tokens = None )
get_identifiers
返回标识符, 不包含空格和标点符号
where
语句
1
sqlparse . sql . Where ( tokens = None )
一个或多个WHEN且可能是ELSE部分的CASE语句
1
sqlparse . sql . Case ( tokens = None )
get_cases(skip_ws = False )
返回两个元组的列表(条件,值)
括号之间的标记
1
sqlparse . sql . Parenthesis ( tokens = None )
** 带有else if
或else
部分的if
子句**
1
sqlparse . sql . If ( tokens = None )
FOR
循环
1
sqlparse . sql . For ( tokens = None )
像var:= val;
这样的赋值
1
sqlparse . sql . Assignment ( tokens = None )
在WHERE
子句中使用的比较
1
sqlparse . sql . Assignment ( tokens = None )
解析limit后的字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import sqlparse
from sqlparse.tokens import Keyword , Number
from sqlparse.sql import IdentifierList , Identifier
def extract_from_part ( parsed ):
from_seen = False
for item in parsed . tokens :
if from_seen :
if item . ttype is Keyword :
return
else :
yield item
elif item . ttype is Keyword and item . value . upper () == 'LIMIT' :
from_seen = True
def extract_limit_identifiers ( token_stream ):
for item in token_stream :
if isinstance ( item , IdentifierList ):
for identifier in item . get_identifiers ():
yield identifier . value
elif item . ttype is Number . Integer :
yield item . value
elif item . ttype is Keyword :
yield item . value
# 通过传入sql语句,解析出limit后的数值
# 例如:limit 100,200,返回值[100,200]
def extract_limit ( sql ):
stream = extract_from_part ( sqlparse . parse ( sql )[ 0 ])
return list ( extract_limit_identifiers ( stream ))
增加where筛选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sqlparse
def add_where ( sql : str , k_and_v : dict ):
# k_and_v:{'num >= ':'200'}
stmt = sqlparse . parse ( sql )[ 0 ]
add_in_where = ''
for k , v in k_and_v . items ():
add_in_where += 'and {}{} ' . format ( k , v )
sql_tmp = []
for i in stmt . tokens :
if 'WHERE' in i . value . upper ():
sql_tmp . append ( ' {}{} ' . format ( i . value , add_in_where ))
sql_tmp . append ( i . value )
sql = '' . join ( sql_tmp )
if 'WHERE' not in sql . upper ():
sql = sql . replace ( 'limit' , 'where {} limit' . format ( add_in_where ))