Python调用SQLPlus来操作和解析Oracle数据库的方法
先来看一个简单的利用python调用sqlplus来输出结果的例子:
importos importsys fromsubprocessimportPopen,PIPE sql=""" setlinesize400 colownerfora10 colobject_namefora30 selectowner,object_name fromdba_objects whererownum<=10; """ proc=Popen(["sqlplus","-S","/","as","sysdba"],stdout=PIPE,stdin=PIPE,stderr=PIPE) proc.stdin.write(sql) (out,err)=proc.communicate() ifproc.returncode!=0: printerr sys.exit(proc.returncode) else: printout
用Python查询Oracle,当然最好用cx_Oracle库,但有时候受到种种限制,不能安装Python第三方库,就得利用现有资源,硬着头皮上了。
用Python调用SqlPlus查询Oracle,首先要知道SqlPlus返回结果是什么样的:
(这是空行) NumberNameAddress ----------------------------------------- 1001张三南京路 1002李四上海路
第1行是空行,第2行是字段名称,第3行都是横杠,有空格隔开,第4行开始是查询到的结果。
在查询结果规整的情况下,根据第3行可以很清晰的看到结构,用Python解析起来也比较方便。但是,如果一张表字段特别多,记录数也相当多,那么默认情况下调用SqlPlus查询出的结果会比较乱,这就需要在调用查询之前做一些设定,比如:
setlinesize32767 setpagesize9999 settermoffverifyofffeedbackofftaboff setnumwidth40
这样的调用查询结果就比较规整了。接下来就是用强大的Python来解析查询结果。
这里封装了一个函数,可以根据传入的SQL语句查询并解析结果,将每行结果存到列表中,列表中的每个元素是一个字段名称与值的映射。
#!/usr/bin/python
#coding=UTF-8
'''
@author:双子座@开源中国
@summary:通过SqlPlus查询Oracles数据库
'''
importos;
os.environ['NLS_LANG']='AMERICAN_AMERICA.AL32UTF8'
gStrConnection='username/password@10.123.5.123:1521/ora11g'
#解析SqlPlus的查询结果,返回列表
defparseQueryResult(listQueryResult):
listResult=[]
#如果少于4行,说明查询结果为空
iflen(listQueryResult)<4:
returnlistResult
#第0行是空行,第1行可以获取字段名称,第2行可获取SQLPlus原始结果中每列宽度,第3行开始是真正输出
#1解析第2行,取得每列宽度,放在列表中
listStrTmp=listQueryResult[2].split('')
listIntWidth=[]
foroneStrinlistStrTmp:
listIntWidth.append(len(oneStr))
#2解析第1行,取得字段名称放在列表中
listStrFieldName=[]
iLastIndex=0
lineFieldNames=listQueryResult[1]
foriWidthinlistIntWidth:
#截取[iLastIndex,iLastIndex+iWidth)之间的字符串
strFieldName=lineFieldNames[iLastIndex:iLastIndex+iWidth]
strFieldName=strFieldName.strip()#去除两端空白符
listStrFieldName.append(strFieldName)
iLastIndex=iLastIndex+iWidth+1
#3第3行开始,解析结果,并建立映射,存储到列表中
foriinrange(3,len(listQueryResult)):
oneLiseResult=unicode(listQueryResult[i],'UTF-8')
fieldMap={}
iLastIndex=0
forjinrange(len(listIntWidth)):
strFieldValue=oneLiseResult[iLastIndex:iLastIndex+listIntWidth[j]]
strFieldValue=strFieldValue.strip()
fieldMap[listStrFieldName[j]]=strFieldValue
iLastIndex=iLastIndex+listIntWidth[j]+1
listResult.append(fieldMap)
returnlistResult
defQueryBySqlPlus(sqlCommand):
globalgStrConnection
#构造查询命令
strCommand='sqlplus-S%s<<!\n'%gStrConnection
strCommand=strCommand+'setlinesize32767\n'
strCommand=strCommand+'setpagesize9999\n'
strCommand=strCommand+'settermoffverifyofffeedbackofftaboff\n'
strCommand=strCommand+'setnumwidth40\n'
strCommand=strCommand+sqlCommand+'\n'
#调用系统命令收集结果
result=os.popen(strCommand)
list=[]
forlineinresult:
list.append(line)
returnparseQueryResult(list)
其中os.environ['NLS_LANG']的值来自
selectuserenv['language']fromdual;在调用的时候,只要类似:
listResult=QueryBySqlPlus('select*fromstudentinfo')
然后就可以用循环打印出结果了。