先來看一個簡單的利用python調用sqlplus來輸出結果的例子:
import osimport sysfrom subprocess import Popen, PIPE sql = """set linesize 400col owner for a10col 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 32767set pagesize 9999set term off verify off feedback off tab offset 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 listResultdef 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')
然后就可以用循環打印出結果了。