Python调用SQLPlus来操作和解析Oracle数据库的方法

Python调用SQLPlus来操作和解析Oracle数据库的方法

这篇文章主要介绍了Python调用SQLPlus来操作和解析Oracle数据库的方法,这样用SQL*Plus方式来分析Oracle中的数据就变得十分方便,需要的朋友可以参考下
先来看一个简单的利用python调用sqlplus来输出结果的例子:

import os
import sys
from subprocess import Popen, PIPE
 
sql = """
set linesize 400
col owner for a10
col object_name for a30
 
select owner, object_name
 from dba_objects
 where rownum<=10;
"""
 
proc = Popen(["sqlplus", "-S", "/", "as", "sysdba"], stdout=PIPE, stdin=PIPE, stderr=PIPE)
proc.stdin.write(sql)
(out, err) = proc.communicate()
 
if proc.returncode != 0:
  print err
  sys.exit(proc.returncode)
else:
  print out

用Python查询Oracle,当然最好用cx_Oracle库,但有时候受到种种限制,不能安装Python第三方库,就得利用现有资源,硬着头皮上了。
用Python调用SqlPlus查询Oracle,首先要知道SqlPlus返回结果是什么样的:

(这是空行)
Number    Name    Address
------------ ----------- ------------------
1001     张三     南京路
1002     李四     上海路

第1行是空行,第2行是字段名称,第3行都是横杠,有空格隔开,第4行开始是查询到的结果。
在查询结果规整的情况下,根据第3行可以很清晰的看到结构,用Python解析起来也比较方便。但是,如果一张表字段特别多,记录数也相当多,那么默认情况下调用SqlPlus查询出的结果会比较乱,这就需要在调用查询之前做一些设定,比如:

set linesize 32767
set pagesize 9999
set term off verify off feedback off tab off
set numwidth 40

这样的调用查询结果就比较规整了。接下来就是用强大的Python来解析查询结果。
这里封装了一个函数,可以根据传入的SQL语句查询并解析结果,将每行结果存到列表中,列表中的每个元素是一个字段名称与值的映射。

#!/usr/bin/python
#coding=UTF-8

'''
@author: 双子座@开源中国
@summary: 通过SqlPlus查询Oracles数据库
'''
import os;
os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.AL32UTF8'
gStrConnection = 'username/password@10.123.5.123:1521/ora11g'
#解析SqlPlus的查询结果,返回列表
def parseQueryResult(listQueryResult):
      listResult = []
      #如果少于4行,说明查询结果为空
      if len(listQueryResult) < 4:
        return listResult
      #第0行是空行,第1行可以获取字段名称,第2行可获取SQLPlus原始结果中每列宽度,第3行开始是真正输出
      # 1 解析第2行,取得每列宽度,放在列表中
      listStrTmp = listQueryResult[2].split(' ')
      listIntWidth = []
      for oneStr in listStrTmp:
        listIntWidth.append(len(oneStr))
      # 2 解析第1行,取得字段名称放在列表中
      listStrFieldName = []
      iLastIndex = 0
      lineFieldNames = listQueryResult[1]
      for iWidth in listIntWidth:
        #截取[iLastIndex, iLastIndex+iWidth)之间的字符串
        strFieldName = lineFieldNames[iLastIndex:iLastIndex + iWidth]
        strFieldName = strFieldName.strip() #去除两端空白符
        listStrFieldName.append(strFieldName)
        iLastIndex = iLastIndex + iWidth + 1
      # 3 第3行开始,解析结果,并建立映射,存储到列表中
      for i in range(3, len(listQueryResult)):
        oneLiseResult = unicode(listQueryResult[i], 'UTF-8')
        fieldMap = {}
        iLastIndex = 0
        for j in range(len(listIntWidth)):
          strFieldValue = oneLiseResult[iLastIndex:iLastIndex + listIntWidth[j]]
          strFieldValue = strFieldValue.strip()
          fieldMap[listStrFieldName[j]] = strFieldValue
          iLastIndex = iLastIndex + listIntWidth[j] + 1
        listResult.append(fieldMap)
      return listResult

def QueryBySqlPlus(sqlCommand):
      global gStrConnection
      #构造查询命令
      strCommand = 'sqlplus -S %s <<!\n' % gStrConnection
      strCommand = strCommand + 'set linesize 32767\n'
      strCommand = strCommand + 'set pagesize 9999\n'
      strCommand = strCommand + 'set term off verify off feedback off tab off \n'
      strCommand = strCommand + 'set numwidth 40\n'
      strCommand = strCommand + sqlCommand + '\n'
      #调用系统命令收集结果
      result = os.popen(strCommand)
      list = []
      for line in result:
        list.append(line)
      return parseQueryResult(list)

#其中os.environ['NLS_LANG']的值来自
select userenv['language'] from dual;

在调用的时候,只要类似:

listResult = QueryBySqlPlus('select * from studentinfo')

然后就可以用循环打印出结果了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 背景: 阅读新闻 12C CDB模式下RMAN备份与恢复 [日期:2016-11-29] 来源:Linux社区 作...
    阳屯okyepd阅读 8,983评论 0 7
  • # Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列...
    aimaile阅读 26,688评论 6 427
  • 环境管理管理Python版本和环境的工具。p–非常简单的交互式python版本管理工具。pyenv–简单的Pyth...
    MrHamster阅读 9,229评论 1 61
  • 夕阳的余晖又一次笼罩大地,风穿过树林送来深秋的叹息,如同过去很多个普普通通的日子一样,一天的光阴即将逝去。去年的今...
    石头姑娘133阅读 1,267评论 0 1
  • 本该早睡却迟迟无眠,蛙声四起忽想起那么一句诗“何当共剪西窗烛”。 无意点开简书,很久没有进来了,不是没有时间,只是...
    60分先生en阅读 1,800评论 0 0