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')
然后就可以用循环打印出结果了。