警告
本文最后更新于 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))
|