Python连接Oracle数据库
1、其实使用Python连接Oracle数据库跟连接Mysql数据库差不多,整体流程以及方法都差不多。只是说在安装cx_Oracle过程中过程中可能会有点坑:特别是连接Oracle时,主要就是需要保证各个组件的版本一致:系统版本,python版本,oracle客户端的版本,cx_Oracle的版本
2、Python连接Oracle数据库依赖于第三方模块cx_Oracle:pip install cx_Oracle==7.2.3
使用流程
简单的使用流程如下:
1、引用模块cx_Oracle
2、连接数据库
3、获取cursor
4、使用cursor进行各种操作
5、关闭cursor
6、关闭连接
Python 类型和Oracle 类型的对应关系
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL51EVPBTR61UNNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwMjMyAzN1MTM5IjMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
Oracle操作
使用Python连接到Oracle数据库共有三种方法:使用connect()函数连接到数据库,返回数据库的连接对象(连接对象的方法与pymysql连接对象的方法一致)
⑴用户名,密码和监听分开写:"用户名","密码","数据库IP:端口号/ServerName"。只需用到connect()方法
⑵用户名,密码和监听写在一起:用户名/密码@数据库IP:端口号/ServerName。只需用到connect()方法
⑶配置监听并连接:需要用到同时用到makedsn()和connect()方法,感觉不是经常用
例1:
import cx_Oracle
import os
import datetime
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
#连接数据库:返回连接对象
db_conn = cx_Oracle.connect("zh/[email protected]:1521/orcl")
#获取游标对象
db_cursor = db_conn.cursor()
#执行SQL语句
db_cursor.execute("""SELECT * FROM user_info WHERE name='张三'""")
#获取查询结果
selectResults = db_cursor.fetchall() # 返回查询结果
#同时获取查询结果对应的列名
colNames = db_cursor.description # 返回查询结果对应列名
print("查询出来的数据为:", selectResults)
print("查询出来的列名为:", colNames)
#关闭连接对象和游标对象
db_cursor.close()
db_conn.close()
"""
查询出来的数据为: [(1, '张三', 'China', datetime.datetime(2020, 9, 10, 20, 34, 23), datetime.datetime(2020, 7, 20, 20, 34, 25, 269000), 1, 4, 2, 2424)]
查询出来的列名为: [('ID', <class 'cx_Oracle.NUMBER'>, 21, None, 20, 0, 0), ('NAME', <class 'cx_Oracle.STRING'>, 20, 60, None, None, 0),
('COUNTRY', <class 'cx_Oracle.STRING'>, 20, 60, None, None, 0), ('DATE_TIME', <class 'cx_Oracle.DATETIME'>, 23, None, None, None, 0),
('TIMESTAMP', <class 'cx_Oracle.TIMESTAMP'>, 23, None, 0, 6, 0), ('DEPT_ID', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1),
('EMPLOYEE_NO', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1), ('LEADER_NO', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1),
('WAGE', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1)]
"""
注:在连接过程中遇到的几个坑
1、cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded....:这个问题的原因大概就是oracle客户端的驱动位数与python的位数不一致造成的
解决办法:
1、下载64位驱动地址:http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html
2、下载驱动压缩包后解压到任意文件夹下
3、将解压后的文件路径添加到环境变量:如path=C:\instantclient-basic-nt-11.2.0.2.0
4、然后设置Oracle的环境变量:Path:%ORACLE_HOME%\bin
5、把下载的文件解压,复制oci,oraocci11,oraociei11的3个DLL粘贴到你的PY目录的Libs/site-packages文件夹下面。
注:设置全部后,一定要重启Pycharm!!!不然会一直报错
2、查询数据中存在中文时,Python返回的中文显示为乱码
解决办法:在脚本前面增加以下代码
import os
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' #或者
os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.AL32UTF8'
综合
一般情况下,数据库的操作都是固定的:增、删、改、查。只是说会出现连接的数据库不同、执行的SQL语句不同。但是基本的连接、执行SQL语句那些是固定的。因此就可以将那些固定的代码编写好,后面具体执行时调用这些代码就好了
⑴将固定的:增、删、改、查,这些操作单独定义成一个类(类方法等)
⑵将数据库信息、执行的SQL语句这些会变的使用变量代替就好了
例2:
import cx_Oracle
import os
import datetime
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
#定义一个基础数据库操作类
class DB():
def __init__(self):
pass
def ConnectDB(self, db_info="zh/[email protected]:1521/orcl"):
try:
db_conn = cx_Oracle.connect(db_info)
db_cursor = db_conn.cursor()
return db_conn, db_cursor
except BaseException:
raise ("数据库连接失败,请检查输入参数")
def SelectSql(self, db_cursor, sql):
db_cursor.execute(sql)
selectResults = db_cursor.fetchall() # 返回查询结果
colNames = db_cursor.description # 返回查询结果对应列名
return selectResults, colNames
"""
下面也可以继续定义数据库的其他操作:增、删、改
"""
#定义一个根据实际场景的数据库操作类:基本的数据数据库操作这些直接调用DB()类即可
class Demo(DB):
#这里采用继承DB()类的方式:并继承其构造方法
def __init__(self):
super().__init__()
def SelectData(self,sql):
#因为采用的是继承:因此,这里调用DB()类的类方法(类变量、实例变量)就相当于是在自己类中调用一样
db_conn, db_cursor = self.ConnectDB()
selectResults, colNames = self.SelectSql(db_cursor, sql)
print("查询出来的数据为:",selectResults)
print("查询出来的列名为:", colNames)
return selectResults,colNames
#定义一个基础的数据处理类:不同场景查询出来的数据和列表都可以使用这个类来进行处理
class DealData():
def __init__(self):
pass
def DealSelectData(self, selectDatas):
"""
处理查询出来的数据
"""
#定义一个大列表来装所有子数据列表:是一个嵌套了列表的列表
selectDataLists = []
for selectData in selectDatas:
#定义一个小列表来装该条数据
selectDataList = []
for eachData in selectData:
#如果字段值为整形、浮点型、字符串:那么不需要整理,直接加入到该条数据列表中
if isinstance(eachData,int) == True or isinstance(eachData,str) == True or isinstance(eachData,float) == True:
selectDataList.append(eachData)
#如果字段值为datetime类型:那么就将其转为字符串型的时间值
elif isinstance(eachData,datetime.datetime):
eachData = eachData.strftime('%Y-%m-%d %H:%M:%S')
selectDataList.append(eachData)
#如果字段值为None:那么就添加null,毕竟数据库中空值表示为null
elif eachData is None:
selectDataList.append("null")
else:
print("该类型的值未整理:请添加相应代码")
selectDataLists.append(selectDataList)
print("整理后的查询数据为:",selectDataLists)
return selectDataLists
def DealColName(self, colNames):
"""
处理查询结果对应的列名
"""
colNamesList = []
for colName in colNames:
colName = colName[0].lower() #同时将列名全部转为小写
colNamesList.append(colName)
print("整理后的列名为:",colNamesList)
return colNamesList
def CreateDict(self,colNamesList,selectDataLists):
"""将查询结果和类名整理成字典"""
selectDataDictList = [dict(zip(colNamesList, selectDataList)) for selectDataList in selectDataLists]
print("最终整理后的查询结果为:",selectDataDictList)
return selectDataDictList
if __name__ == "__main__":
demo = Demo()
selectResults, colNames = demo.SelectData(sql = """SELECT * FROM user_info""")
dealData = DealData()
selectDataLists = dealData.DealSelectData(selectResults)
colNamesList = dealData.DealColName(colNames)
dealData.CreateDict(colNamesList,selectDataLists)
"""
查询出来的数据为: [(1, '张三', 'China', datetime.datetime(2020, 9, 10, 20, 34, 23), datetime.datetime(2020, 7, 20, 20, 34, 25, 269000), 1, 4, 2, 2424), (2, '李四', 'China', datetime.datetime(2022, 7, 5, 20, 34, 58), datetime.datetime(2020, 7, 19, 12, 35, 1), 2, 2, 3, 7747), (3, '王五', 'China', datetime.datetime(2020, 7, 20, 21, 18, 16), datetime.datetime(2020, 7, 20, 21, 18, 16), 2, 3, 4, 4242), (7, 'LL', 'yy', datetime.datetime(2020, 7, 30, 20, 30, 30), datetime.datetime(2020, 7, 30, 20, 30, 30, 123000), 1, 2, 1, 41474), (4, '李六', 'China', datetime.datetime(2020, 7, 30, 20, 30, 30), datetime.datetime(2020, 7, 30, 20, 30, 30, 555550), 3, 1, 5, 74757)]
查询出来的列名为: [('ID', <class 'cx_Oracle.NUMBER'>, 21, None, 20, 0, 0), ('NAME', <class 'cx_Oracle.STRING'>, 20, 60, None, None, 0), ('COUNTRY', <class 'cx_Oracle.STRING'>, 20, 60, None, None, 0), ('DATE_TIME', <class 'cx_Oracle.DATETIME'>, 23, None, None, None, 0), ('TIMESTAMP', <class 'cx_Oracle.TIMESTAMP'>, 23, None, 0, 6, 0), ('DEPT_ID', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1), ('EMPLOYEE_NO', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1), ('LEADER_NO', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1), ('WAGE', <class 'cx_Oracle.NUMBER'>, 127, None, 0, -127, 1)]
整理后的查询数据为: [[1, '张三', 'China', '2020-09-10 20:34:23', '2020-07-20 20:34:25', 1, 4, 2, 2424], [2, '李四', 'China', '2022-07-05 20:34:58', '2020-07-19 12:35:01', 2, 2, 3, 7747], [3, '王五', 'China', '2020-07-20 21:18:16', '2020-07-20 21:18:16', 2, 3, 4, 4242], [7, 'LL', 'yy', '2020-07-30 20:30:30', '2020-07-30 20:30:30', 1, 2, 1, 41474], [4, '李六', 'China', '2020-07-30 20:30:30', '2020-07-30 20:30:30', 3, 1, 5, 74757]]
整理后的列名为: ['id', 'name', 'country', 'date_time', 'timestamp', 'dept_id', 'employee_no', 'leader_no', 'wage']
最终整理后的查询结果为: [{'leader_no': 2, 'wage': 2424, 'name': '张三', 'dept_id': 1, 'employee_no': 4, 'country': 'China', 'date_time': '2020-09-10 20:34:23', 'id': 1, 'timestamp': '2020-07-20 20:34:25'}, {'leader_no': 3, 'wage': 7747, 'name': '李四', 'dept_id': 2, 'employee_no': 2, 'country': 'China', 'date_time': '2022-07-05 20:34:58', 'id': 2, 'timestamp': '2020-07-19 12:35:01'}, {'leader_no': 4, 'wage': 4242, 'name': '王五', 'dept_id': 2, 'employee_no': 3, 'country': 'China', 'date_time': '2020-07-20 21:18:16', 'id': 3, 'timestamp': '2020-07-20 21:18:16'}, {'leader_no': 1, 'wage': 41474, 'name': 'LL', 'dept_id': 1, 'employee_no': 2, 'country': 'yy', 'date_time': '2020-07-30 20:30:30', 'id': 7, 'timestamp': '2020-07-30 20:30:30'}, {'leader_no': 5, 'wage': 74757, 'name': '李六', 'dept_id': 3, 'employee_no': 1, 'country': 'China', 'date_time': '2020-07-30 20:30:30', 'id': 4, 'timestamp': '2020-07-30 20:30:30'}]
"""
例2_1:使用上面的写法时,在调用查询等函数时还需要传入一个db_cursor(数据库里游标对象),就显得很麻烦,最好的还是将连接对象、游标对象定义成实例变量
import cx_Oracle
import os
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
class ConnectDb():
"""
定义一个基础数据库操作类
数据库连接对象、游标对象,在很多方法中都需要用到,因此将其定义为实例变量
不同地方连接,肯定得是不同的实例
"""
def __init__(self):
# 连接对象和游标对象是很多方法都需要用到的,因此将其定义为实例变量
#因为这两个是实例变量,因此不同的连接实例之间是不会相互影响的
self.db_conn = None
self.db_cursor = None
def Connect(self,userName,passWord,Ip,port,serverName):
"""单独定义一个方法来连接数据库:获取连接对象和游标对象"""
db_info = "%s/%s@%s:%s/%s" % (userName,passWord,Ip,port,serverName)
# 对实例变量重新赋值self.db_conn,self.db_cursor,因为是实例变量,因此不同实例之间是互不影响
self.db_conn = cx_Oracle.connect(db_info)
self.db_cursor = self.db_conn.cursor()
# 这里两个返回值实际上是用不到的self.db_conn,self.db_cursor,实际用的是实例变量self.db_conn,self.db_cursor
# 前面对实例变量重新赋值后,就相当于在内存中了,直接使用就好了
return self.db_conn,self.db_cursor
def Query(self,sql):
"""数据库查询"""
self.db_cursor.execute(sql)
queryResults = self.db_cursor.fetchall()
return queryResults
def Insert(self,sql):
"""数据库插入"""
try:
self.db_cursor.execute(sql)
# 提交到数据库执行
self.db_conn.commit()
print('插入数据成功')
except Exception: # 常规错误的基类
print("插入数据失败")
# 如果发生错误就回滚
self.db_conn.rollback()
def Close(self):
"""关闭数据库连接"""
self.db_cursor.close() # 先关闭游标
self.db_conn.close() # 再关闭数据库连接
# d导入所需模块
from demo.zsd import ConnectDb
class Demo(ConnectDb):
#这里采用继承的方式并继承其构造方法
def __init__(self,userName, passWord, Ip, port, serverName):
super().__init__()
# 这些数据库信息实例变量也可以定义在ConnectDb类中的实例变量里面,反正看怎么写方便
self.userName = userName
self.passWord = passWord
self.Ip = Ip
self.port = port
self.serverName = serverName
# 调用数据库连接方式
self.Connect(self.userName,self.passWord,self.Ip,self.port,self.serverName)
# 也可以这么写(将返回值设置为实例变量),但没啥影响,这里的self.connect, self.course实际不会用到
# 实际用到的还是ConnectDb类中的self.db_conn,self.db_cursor
# self.connect, self.course = self.Connect(self.userName,self.passWord,self.Ip,self.port,self.serverName)
def Test(self,sql):
queryResults = self.Query(sql)
self.Close()
return queryResults
demo1 = Demo("zhouhao","123456","localhost","1521","orcl")
queryResults1 = demo1.Test("SELECT * FROM FRUITS")
print(queryResults1)
demo2 = Demo("zhouhao","123456","localhost","1521","orcl")
queryResults2 = demo2.Test("SELECT * FROM FRUITS WHERE F_ID>4")
print(queryResults2)
"""
[(3, 'apple'), (4, 'origin'), (5, 'APPLE')]
[(5, 'APPLE')]
"""
实例
1、目前在工作中用到的Oracle的场景是:使用Postman发送接口URL、Body等去请求数据库某个表中的数据,然后查看请求返回的数据是否与数据库中的数据一致。有时数据库中的字段少的话还好,手动对比就能对比完,但是特么有几个表中的字段有100多个,然后就没心思去对比了而且也容易对比错,所以自己就写了个脚本去对比
2、主要思路是:一方面将Postman的数据手动复制出来存到一个TXT或者Json文件中(Postman返回的是一个JSon型字符串)。另一方面通过脚本执行指定的SQL语句去查询数据库中的对应数据,然后将查询出来的数据以及其列名组成一个字典。把Postman返回的数据与查询出来的数据进行对比。对比方式为将返回数据中的键值拿出来,通过键名去找查询出来的数据的值,然后看两个值对不对
3、Postman返回的数据格式和数据库中的数据格式如下:通过下面数据对比,我们主要注意的是有几个地方需要我们去转化下
⑴返回数据的键名与数据库的列名不一致,通过对比可以发现:返回数据的键名就是数据列名中去掉"_"号,每个开头字母大写其余小写的
⑵数据库中的值一般有五种:数字、字符串、浮点数、日期、null(特别是null,这种数据类型在Python中什么都不是,既不是字符串也不是None,所以更需要单独转换)
#Postman返回的数据格式
{
"plegId": 11170260,
"ambFltid": "143564",
"plegFltno": "张三",
"plegShare": null,
"plegDate": "2019-12-25 09:39:21"
}
#数据库中的数据格式如下
{
"PLEG_ID" : 11170260,
"AMB_FLTID" : "143564",
"PLEG_FLTNO" : "张三",
"PLEG_SHARE" : null,
"PLEG_DATE" : "2019-12-25T01:39:21Z"
}
例2_1:
# -*- coding: utf-8 -*-
# @Time : 2019/11/26 0026 22:24
# @Author : 不怕猫的耗子A
import json
import datetime
import cx_Oracle
import os
def GetResonseData(filePath):
"""
作用:
1、根据指定路径获取存放Postman返回数据的文件并读取其中的数据
2、将返回数据中的键名进行处理:这里我想得办法是,把数据库的列名、返回数据的键名都转为小写,这样就好对比了
3、返回数据中的null我没有在脚本中处理,采用的是手动替换,实际也可以在脚本中处理
param filePath: 存放Postman返回数据的文件
return:返回处理了键名的字典
"""
responseDataDict = {}
with open(filePath, 'r', encoding='utf-8') as file:
responseData = json.loads(file.read())
for responseDataKey, responseDataValue in responseData.items():
responseDataDict[responseDataKey.lower()] = responseDataValue#将键名转为小写并重组为字典
return responseDataDict
def GetSelectData(sql):
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.AL32UTF8'
# 引用模块cx_Oracle
conn = cx_Oracle.connect('用户名/密码@数据库IP:端口号/ServerName') # 连接数据库
cursor = conn.cursor() # 创建游标
cursor.execute(sql) # 执行sql语句
selectData = cursor.fetchone() # 获取一条数据
#print(selectData)
# print(cursor.description)#获取列名
databaseColList = []
for i in cursor.description:
databaseColList.append("".join((i[0].split("_"))).lower())#对查询到的列名进行处理
# databaseColList = [i[0] for i in cursor.description]#这里注释了的用的列表生成式,作用跟上面一行才不多,感觉这样写好点
# databaseCol = []
# for n in databaseColList:
# databaseCol.append(("".join(n.split("_")).lower()))
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
selectDataList = []
for i in selectData:
if type(i) == str or type(i) == int or type(i) == float:
selectDataList.append(i)
# else:
# try:
# i = i.strftime("%Y-%m-%d %H:%M:%S")
# selectDataList.append(i)
# except AttributeError:
# #查询的数据中有null值,如果进行strftime()操作时会触发AttributeError异常,所以可以加一个异常处理来强制把null加到列表中
# selectDataList.append("null")
elif type(i) == datetime.datetime:#值类型为datetime.datetime对象的话
i = i.strftime("%Y-%m-%d %H:%M:%S")
selectDataList.append(i)
else:
selectDataList.append("null")
selectDataDict = dict(zip(databaseColList, selectDataList))
return selectDataDict
注:
1、上面代码估计是一个人都看不怎么懂,没办法个人水平在这里,如果有幸看到,请不要嫌弃
2、在写这个脚本过程中,感觉难点还是对返回数据和查询数据的键名进行处理以及对查询数据的值进行处理(日期格式的值和null值)
3、对于键名的处理刚开始自己想了很多该怎么从一个键名去找另一个字典中对应的键名,什么正则表达式呀等等都想过(因为返回数据中有大写有小写)不过写着写着就突然想到,要不就两个数据的键名都统一转为小写或大写就好了
拓展
上面例子中有几个知识点,感觉可以补充下
文件读取
1、Python读取TXT、JSON文件:两个差不多可以当成一个东西来处理
⑴在读取文件时,我们可能需要一行一行的读取出来:这种就可以对文件对象进行for循环遍历或者使用对应方法,如readline、readlines
⑵同时我们也可能需要一下就将整个文件都读出来,并且需要保证其格式(不是数据类型):此时就可以使用read()方法,read()方法如果没有参数的话,就是将文件中全部的内容一次性读出来
例3:
import json
#
# import json
#
# 从文件中读取json并转化为python数据
#
# path = "C:\\Py_Demo\\test.json"
#
# with open(path, 'r', encoding="utf-8") as file: # 在代码当前目录生成一个data.json的文件
# json_data = json.load(file)#读取出来时为字符串类型,所以需要转换
# print(json_data)
import json
file = open('C:\\Py_Demo\\test.txt', 'r', encoding="utf-8")
js = file.read()#读取出来时为字符串类型,所以需要转换
dic = json.loads(js)
print(dic)
file.close()
列表生成式
将一些元素处理后添加到一个列表中:如果元素的处理逻辑比较简单,那么就可以直接使用列表生成式来将这些元素添加到列表中。这种操作其实挺方便的,特别是不会出现缩进的问题
例4:
string = "hello,word"
#将string中的每个元素转换成大写后添加到一个列表中
list = [i.upper() for i in string]
print(list)
list1 = []
for n in string:
list1.append(n.upper())
print(list1)
"""
当然列表生成式中还可以加入if判断等,具体的可以查询"高级函数那章"
['H', 'E', 'L', 'L', 'O', ',', 'W', 'O', 'R', 'D']
['H', 'E', 'L', 'L', 'O', ',', 'W', 'O', 'R', 'D']
"""
例4_1:
import pymysql
def dbConnect():
dbMysql = pymysql.connect(user="root", password="123456", host="localhost", database="demo", port=3306)
dbCursor = dbMysql.cursor()
SQL = "SELECT roleId,LEVEL,userId,funcelUUid,roleName FROM roleinfo WHERE roleId=5529676068169717607"
execute = dbCursor.execute(SQL)#可以将其返回值赋值给一个变量,不过一般都没有这么做
print(execute)#返回执行SQL语句后影响的行数,一般这个感觉没啥用
data = dbCursor.fetchone()#数据
col = dbCursor.description#列名
dbCursor.close()
dbMysql.close()
return data,col
if __name__ == "__main__":
data,col = dbConnect()
print(data)
print(col)
colList = [i[0] for i in col]
#上面使用的时列表生成式,作用跟下面三行注释的语句一样
# colList = []
# for i in col:
# colList.append(i[0])
print(colList)
print(dict(zip(colList,data)))#Zip()函数:将任意两个序列组合成字典
"""
1
(5529676068169717607, 107, 5529676068164933051, 'b74f7a67f0e8a0d0ecf6265e9a7ebc68', 'Sam_林')
(('roleId', 8, None, 8, 8, 0, False), ('LEVEL', 3, None, 4, 4, 0, False), ('userId', 8, None, 8, 8, 0, False), ('funcelUUid', 253, None, 512, 512, 0, False), ('roleName', 253, None, 256, 256, 0, False))
['roleId', 'LEVEL', 'userId', 'funcelUUid', 'roleName']
{'funcelUUid': 'b74f7a67f0e8a0d0ecf6265e9a7ebc68', 'LEVEL': 107, 'roleId': 5529676068169717607, 'userId': 5529676068164933051, 'roleName': 'Sam_林'}
"""
将一个列表里面的元素拼接成一个字符串
例5:
item1 = ["lowman", "isbusy"]
item2 = "123"
item3= ",".join(item1) # 根据实际需要使用相应的分隔符连接列表元素,如 , : ; 或者空字符串
print(item3)
print(type(item3))
print(item2.join(item3))
string = 'SWFEG_CSD_HSOJDFOS'
colNameString = ''
for i in string.split("_"):#split()方法返回的是一个列表
colNameString += i.capitalize()#capitalize()首字母大写,其余小写
print(colNameString)
colNameList = []
for i in string.split("_"):
colNameList.append(i.capitalize())#capitalize()首字母大写,其余小写
print(colNameList)
colNameString_1 = ''.join(colNameList)
print(colNameString_1)
"""
lowman,isbusy
<class 'str'>
l123o123w123m123a123n123,123i123s123b123u123s123y
SwfegCsdHsojdfos
['Swfeg', 'Csd', 'Hsojdfos']
SwfegCsdHsojdfos
"""
注:
1、Python将一个列表里面的元素拼接成一个字符串,列表里面的元素必须全是字符串才可以使用.join()进行拼接
2、返回的是一个字符串
3、join()方法主要用于:该方法用于将任意序列中的字符串元素以指定符号连接起来。如:用一个字符串将另一个字符串中各元素连接起来(用于连接的字符串可以是符号)
字典的更新
有时候需要单独更新字典的键或值,因此可以使用下面的方法
例6:
s = {
"REG_ID" : 11170260,
"RG_FRG" : "143564",
"GREG_EGJ" : "张三",
"REG_SEEW" : "null",
"GEE_G4" : "2019-12-25T01:39:21Z"
}
dicta = {}
for i in s:
dicta[i.lower()] = s[i]#更新字典的键
print(dicta)
dictb = {}
count = 1
for n in s:
dictb[n] = count#更新字典的键
count += 1
print(dictb)
#利用字典的更新特性来计数或去重
l = [1,2,3,4,2,1,1]
dic = {}
count = 1
for i in l:
if i in dic:
#dic[i] += 1
dic[i] = dic[i] + 1
else:
dic[i] = count
print(dic)
"""
{'rg_frg': '143564', 'gee_g4': '2019-12-25T01:39:21Z', 'reg_seew': 'null', 'reg_id': 11170260, 'greg_egj': '张三'}
{'REG_ID': 1, 'GREG_EGJ': 2, 'RG_FRG': 3, 'REG_SEEW': 5, 'GEE_G4': 4}
{1: 3, 2: 2, 3: 1, 4: 1}
"""
查询数据处理
1、前面说到Oracle数据库中的数据类型与Python数据类型的对应关系,主要有如下表格中的区别:
2、因此直接从数据库中查询出来的数据可能需要处理一下(转换下类型等),才能变成Python中的数据类型
⑴特别是null:在Python中是没有null的,Python中使用None来表示null的(None表示空值,它是一个特殊Python对象, None的类型是NoneType)
3、比如在做自动化时,需要将使用Postman请求(等同于使用Python中的requests请求)返回的数据与数据库中的原始数据比较,以确定请求返回的数据是否正确
Oracle | Python |
NUMBER | int |
CLOB | cx_Oracle.LOB |
TIMESTAMP | datetime.datetime |
VARCHAR2 | str |
DATE | datetime.datetime |
null | None |
例7:
使用Postman请求获得的数据
{
"ID": "100010199727",
"Content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<note> \n <to>Tove</to> \n <from>Jani</from> \n <heading>Reminder</heading> \n <body>Don't forget me this weekend!</body> \n</note>"
"Time": "2020-06-24 09:11:32.000",
"Type": "STB",
"New": 30,
"Old": null 如果使用requests请求的话就是None
}
使用Python操作Oacle查询出来的数据
(100010199727, <cx_Oracle.LOB object at 0x0000022B4F011C88>, datetime.datetime(2020, 6, 24, 9, 11, 32), 'STB', 30, None)
注:
对比上面两种方式返回的数据,可以看出来两者之间的数据还是有很大区别的,肯定是不能直接进行比较的,因此需要对两边的数据进行一些处理
⑴Postman返回的"Content"字段是一个字符串,但是使用Python查询出来的数据是一个对象(<cx_Oracle.LOB object at 0x0000022B4F011C88>)
⑵Postman返回的"Time"字段是一个字符串,但是使用Python查询出来的数据是一个未格式化的时间函数
⑶Postman返回的"Old"字段是一个null,但是使用Python查询出来的数据是一个None
处理思路
1、对Postman返回的数据进行处理:处理成一个字典,对键名、值的处理
2、对Python返回的数据进行处理:处理成一个字段(列名:值,构成的一个字典),对列名、值的处理
3、将前面两个字典的键名、值处理来一样,然后使用集合方法进行比对:因为比对时会区分大小写,所以在处理键名、列名时需要注意
例7_1:
import datetime
class DealData():
def __init__(self):
pass
def DealRsponseData(self,responseData):
"""
#处理Postman返回数据
返回字段名:AAABBB->aaabbb
返回字段值:null->"null"等
:param responseData: Postman返回数据(经初步处理后的Json)
:return: 返回处理后的字典
"""
responseDataDict = {}
for eachKey in responseData:
if isinstance(responseData[eachKey],str) or isinstance(responseData[eachKey], int) or isinstance(responseData[eachKey], float):
responseDataDict[eachKey.lower()] =responseData[eachKey]
elif responseData[eachKey] is None: #这里使用Python中的requests请求的话,数据库中的null就返回的是None,
# 如果是Postman请求的话返回的是null,那么这里就不能这么写了
responseDataDict[eachKey.lower()] = "null"
return responseDataDict
def DealSelectData(self, selectData):
"""
#处理单条查询出来的数据
:param selectData: 查询出来的数据(单条)
:return: 根据实际需要处理后的查询数据列表
"""
selectDataList = []
for eachData in selectData:
if isinstance(eachData, str) or isinstance(eachData, int) or isinstance(eachData, float):
selectDataList.append(eachData)
elif isinstance(eachData, datetime.datetime):
eachData = eachData.strftime("%Y-%m-%d %H:%M:%S")
selectDataList.append(eachData)
elif eachData is None:
selectDataList.append("null")
elif str(type(eachData)) == "<class 'cx_Oracle.LOB'>":
selectDataList.append(eachData.read())
return selectDataList
def DealColName(self,colName):
"""
#用于处理XXX表中的列名:AAA_BBB_CCC->bbbccc
:param colName:使用cursor.description属性返回的列名元组
:return:返回处理后的列名列表
"""
colNameList = []
for eachColName in colName:
eachColName = eachColName[0].split("_", 1)[1].lower().replace("_", "")
colNameList.append(eachColName)
return colNameList
注:
其实其他的处理还是比较简单的,主要是想说明下对cx_Oracle.LOB 类型的处理方式:使用read()函数来读取这个类型下的字符串
⑴在遍历查询出来的数据时,获得clob或LOB对象a,使用a.read()
⑵Postman返回的是null,Python返回的是一个None,因此都处理两个数据(都转换为字符串形式的null):null和字符串null肯定是不能比较的