CREATE TABLE TABLE_TO_CREATE NOLOGGING AS
SELECT DISTINCT
A.COLA,
B.COLB,
DECODE(A.DECODE_CONDITION, 1, '是', '否') DECODED,
ROW_NUMBER() OVER(PARTITION BY A.CLASS_CONDITION ORDER BY A.RAND_CONDITION DESC) RN
FROM FSCRM.TABLE_A A,
(SELECT * FROM TABLE_C C WHERE C.SOMETHING='SOMETHING' AND C.NUM=1234) B
WHERE A.COMPARE_CONDITION=B.COMPARE_CONDITION
AND A.NUM NOT IN (1, 2, 3)
AND NOT EXISTS (SELECT D.COLD FROM TABLE_D WHERE A.COLA=D.COLD)
ORDER BY A.ORDER_CONDITION
/* COMMENTS */
了解过sqlparse的人都知道,使用parse后,sql语句被解析成一棵树。这棵树跟常见的树不一样,因为它的父节点,是完全包含了子节点的信息。例如在上面的例子:
In [1]: import sqlparse
In [2]: with open('sample.sql', 'r', encoding='utf8') as sql_file:
...: file_parse = sqlparse.parse(sql_file.read().strip())
In [3]: file_parse
Out[3]: (<Statement 'CREATE...' at 0x49E6CF0>,)
In [4]: for token in file_parse[0].tokens:
...: print(type(token), token.ttype, token.value)
<class 'sqlparse.sql.Token'> Token.Keyword.DDL CREATE
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword TABLE
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Identifier'> None TABLE_TO_CREATE NOLOGGING
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword AS
<class 'sqlparse.sql.Token'> Token.Text.Whitespace.Newline
<class 'sqlparse.sql.Token'> Token.Keyword.DML SELECT
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword DISTINCT
<class 'sqlparse.sql.Token'> Token.Text.Whitespace.Newline
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.IdentifierList'> None A.COLA,
B.COLB,
DECODE
<class 'sqlparse.sql.IdentifierList'> None (A.DECODE_CONDITION, 1, '是', '否')
ECODED,
ROW_NUMBER
<class 'sqlparse.sql.Identifier'> None () OVER
<class 'sqlparse.sql.Identifier'> None (PARTITION BY A.CLASS_CONDITION ORDER BY
A.RAND_CONDITION DESC) RN
<class 'sqlparse.sql.Token'> Token.Text.Whitespace.Newline
<class 'sqlparse.sql.Token'> Token.Keyword FROM
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.IdentifierList'> None FSCRM.TABLE_A A,
(SELECT * FROM TABLE_C C WHERE C.SOMETHING='SOMETHING' AND C.NU
=1234) B
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Where'> None WHERE A.COMPARE_CONDITION=B.COMPARE_CONDITION
AND A.NUM NOT IN (1, 2, 3)
AND NOT EXISTS (SELECT D.COLD FROM TABLE_D WHERE A.COLA=D.COLD)
<class 'sqlparse.sql.Token'> Token.Keyword ORDER
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword BY
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Identifier'> None A.ORDER_CONDITION
/* COMMENTS */
<class 'sqlparse.sql.Token'> Token.Punctuation ;
这里要提醒一下的就是,从上面的out[3]大家可以看到parse语句返回的是一个tuple,就算只有一个statement,也是一个tuple,所以我们在使用的时候需要加上下标[0]。
解析出来的statement其实也是token的一个子类,而如果token的is_group是True的话(这个group跟sql的group不是一回事),每个token都有tokens属性,存了一个子token的list。当我们遍历后会发现,里面的数据类型除了基本类型Token,还有Where,Identifier,IdentifierList等等,这些都是继承了Token的子类,但大多没有额外的方法,基本就是多了一些声明包含关键字的常量,都是类属性。而我们查看ttype这个属性,主要是标注了一些关键字或者标点符号如空格、括号、分号等。我们进行选择的时候可以通过ttype做个初步的筛选。而value存的是这个token的整个语句,即便是它是一个group,里面有很多子token,它也是完全存了所有子token拼成的整个语句。所以当我们使用子token的parent属性时,很容易就可以找到父结点的整句sql语句。
下面我们来介绍Identifier和IdentifierList:
In [10]: identifier_list = file_parse[0].tokens[13]
In [11]: identifier_list
Out[11]: <IdentifierList 'A.COLA...' at 0x4BCD138>
In [12]: identifier_list.get_identifiers()
Out[12]: <generator object IdentifierList.get_identifiers at 0x0000000004C22BF8>
In [13]: for identifier in identifier_list.get_identifiers():
...: print(type(identifier), identifier.ttype, identifier.value)
<class 'sqlparse.sql.Identifier'> None A.COLA
<class 'sqlparse.sql.Identifier'> None B.COLB
<class 'sqlparse.sql.Identifier'> None DECODE
In [14]: for identifier in identifier_list.get_identifiers():
...: print(type(identifier), identifier.ttype, identifier.value, identi
...: fier.get_real_name())
<class 'sqlparse.sql.Identifier'> None A.COLA COLA
<class 'sqlparse.sql.Identifier'> None B.COLB COLB
<class 'sqlparse.sql.Identifier'> None DECODE DECODE
从上述代码可以看到,IdentifierList比普通的token多了一个方法get_identifiers方法,返回的是一个Identifier的列表,而每个Identifier可以使用get_real_name来获取真名,这个用在提取字段名和表名的时候非常有用。
最后一个想介绍的就是Where类型,这个类型下面主要是一系列的条件:
In [4]: where = file_parse[0].tokens[22]
In [5]: where
Out[5]: <Where 'WHERE ...' at 0x49E6E58>
In [6]: for token in where.tokens:
...: print(type(token), token.ttype, token.value)
<class 'sqlparse.sql.Token'> Token.Keyword WHERE
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Comparison'> None A.COMPARE_CONDITION=B.COMPARE_CONDITION
<class 'sqlparse.sql.Token'> Token.Text.Whitespace.Newline
<class 'sqlparse.sql.Token'> Token.Keyword AND
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Identifier'> None A.NUM
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword NOT
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword IN
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Parenthesis'> None (1, 2, 3)
<class 'sqlparse.sql.Token'> Token.Text.Whitespace.Newline
<class 'sqlparse.sql.Token'> Token.Keyword AND
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword NOT
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Token'> Token.Keyword EXISTS
<class 'sqlparse.sql.Token'> Token.Text.Whitespace
<class 'sqlparse.sql.Parenthesis'> None (SELECT D.COLD FROM TABLE_D WHERE A.COLA
=D.COLD)
<class 'sqlparse.sql.Token'> Token.Text.Whitespace.Newline
这里重点要看的是,对于比较语句,有个特别的token子类叫Comparison,但是诸如not in、not exist等特殊语句,在这里面是拆分成几个token的,这点比较不友好。我们在编程的时候如果要计算条件数,不能直接数token数,计算and的个数比较好。
最后在提几个小细节,如果我们不想按层次去遍历语句,工具包提供了一个方法flatten,直接可以把所有子、孙结点平铺输出:
In [9]: for id, item in enumerate(where.flatten()):
...: print(id, item.value)
0 WHERE
4 COMPARE_CONDITION
8 COMPARE_CONDITION
10 AND
14 NUM
16 NOT
18 IN
30 AND
32 NOT
34 EXISTS
37 SELECT
41 COLD
43 FROM
45 TABLE_D
47 WHERE
51 COLA
55 COLD
这个种方式的用途之一可以一次过查找所有子查询,然后通过parent语句找出父节点:
In [11]: for item in file_parse[0].flatten():
...: if item.ttype is sqlparse.tokens.Keyword.DML and item.value.upper(
...: ) == 'SELECT':
...: print(item.parent)
CREATE TABLE TABLE_TO_CREATE NOLOGGING AS
SELECT DISTINCT
A.COLA,
B.COLB,
DECODE(A.DECODE_CONDITION, 1, '是', '否') DECODED,
ROW_NUMBER() OVER(PARTITION BY A.CLASS_CONDITION ORDER BY A.RAND
_CONDITION DESC) RN
FROM FSCRM.TABLE_A A,
(SELECT * FROM TABLE_C C WHERE C.SOMETHING='SOMETHING' AND C.NUM
=1234) B
WHERE A.COMPARE_CONDITION=B.COMPARE_CONDITION
AND A.NUM NOT IN (1, 2, 3)
AND NOT EXISTS (SELECT D.COLD FROM TABLE_D WHERE A.COLA=D.COLD)
ORDER BY A.ORDER_CONDITION
/* COMMENTS */
(SELECT * FROM TABLE_C C WHERE C.SOMETHING='SOMETHING' AND C.NUM=1234)
(SELECT D.COLD FROM TABLE_D WHERE A.COLA=D.COLD)
以上就是sqlparse的解析过程,实践出真知,大家可以在解析的过程中多输出各个token的类型、属性,借此来深入了解这个工具包。希望本文对你有所帮助。
sqlparse是Python的一个解析SQL语言的库,安装和文档我也不累赘说了,提供一下官网的地址python-sqlparse,在官网给出的github库里面,有一个提取表名的example,挺好用的,大家可以直接使用。官方的文档比较简单,所以我希望在这篇文章里面补充一些信息,帮助大家理解文档和使用这个工具包。sqlparse有几个最简单的工具:split,format,parse,分别是提取...
然后,假设你有一个类似 dis 的 sql 文件:
CREATE TABLE foo (n integer );
INSERT INTO foo VALUES ( 1 ), ( 2 ), ( 3 );
SELECT * FROM foo
WHERE n > 1 ;
称之为example.sql 。 现在,使用 ,我们可以测试一下:
$ http -f POST http://localhost:5000/split sql=@example.sql
re.search('update',line.sql)
re.search('insert',line.sql)
re.search('delete',line.sql):
2、 使用python中的sqlparse 进行...
python-
sqlparse-解析
SQL语句
sqlparse是用于
Python的非验证
SQL解析器。 它提供了对
SQL语句的解析,拆分和格式化的支持。
该模块与
Python 3.5+兼容,并根据的条款。
访问项目页面,为以获取有关该项目的更多信息。
$ pip install
sqlparse
>> > import
sqlparse
>> > # Split a string containing two
SQL statements:
>> > raw = 'select * from foo; select * from bar;'
>> > statements =
sqlparse . split ( raw )
>> > statements
[ 'select * from foo;' , 'select * from bar;' ]
在项目开发中, 涉及到对SQL语句的展示, 对于复杂的SQL语句, 特别希望能够将其格式化后展示, 因此找到了开源项目sqlparser, 官网是https://github.com/andialbrecht/sqlparse。
使用Python2安装以后可以直接使用, 测试代码:
使用python2,
import sqlparse
print(sqlparse.format('update t set s=(case when total > 100 then 10 when total >=10 and total100 then 8 when YY>10 and yy<100 then 6 else 4 end ) else 2 end)', reindent=False))
一个数据
分析团队往往会积累大量基于
SQL的代码,用于日常的报表,模型数据提取,业务决策等等。有时随着公司的发展和技术更替,公司的数据仓库会进行迁移或重构,当表结构,字段名或者表名发生变化时,包含这些表的
SQL代码就需要相应地进行改写。人为改写一段段业务代码,尤其是对字段或者表名的修改,往往比较重复而且容易遗漏。
懒惰是程序员的第一生产力,既然是重复的工作,那么有没有什么工具可以帮助我们自动化这一过程呢?
2
sqlparse开源库
2.1 介绍
想要改写
SQL代码,关键的一步是对
SQL进
Python是一种强大的编程语言,它具有广泛的应用领域,其中数据分析是其中之一。Python在数据分析方面的应用非常广泛,它可以进行数据处理、数据可视化、机器学习等等。以下是使用Python进行数据分析的一些步骤和工具:
1. 数据预处理:在数据分析之前,我们需要对数据进行预处理,包括数据清洗、数据转换和数据归一化等。Python中常用的数据预处理工具有pandas、numpy和scikit-learn等。
2. 数据可视化:数据可视化可以帮助我们更好地理解数据,包括数据的分布、趋势和异常值等。Python中常用的数据可视化工具有matplotlib、seaborn和plotly等。
3. 数据分析:数据分析是指对数据进行统计分析、机器学习和深度学习等技术处理以提取有价值的信息。Python中常用的数据分析工具有scikit-learn、tensorflow和keras等。
4. 数据报告:最后,我们需要将分析结果整理成报告,用于展示和分享。Python中常用的报告工具有jupyter notebook和pandas等。
总之,Python在数据分析领域有着广泛的应用和丰富的工具库,掌握Python数据分析技能可以帮助我们更好地理解和利用数据。