python操作oracle數據庫-查詢
參照文檔
http://www.oracle.com/technetwork/cn/articles/dsl/mastering-oracle-python-1391323-zhs.html
http://cx-oracle.readthedocs.io/en/latest/module.html
DB API 2.0 和 cx_Oracle 介紹
Python 數據庫 API 規范 v2.0 是集體努力的成果,用於統一不同數據庫系統的訪問模型。擁有一組相對較少的方法和屬性,在更換數據庫供應商時就易於學習並保持一致。它不以任何方式將數據庫對象映射到 Python 結構中。用戶仍然需要手工編寫 SQL。在更換到另一數據庫后,此 SQL 可能需要重新編寫。盡管如此,它還是出色妥善地解決了 Python 數據庫的連接性問題。
該規范定義了 API 的各個部分,如模塊接口、連接對象、游標對象、類型對象和構造器、DB API 的可選擴展以及可選的錯誤處理機制。
數據庫和 Python 語言之間的網關是連接對象。它包含制作數據庫驅動的應用程序所需的全部組件,不僅符合 DB API 2.0,而且是規范方法和屬性的一個超集。在多線程的程序中,模塊和連接可以在不同線程間共享,但是不支持游標共享。這一限制通常是可接受的,因為共享游標可能帶來死鎖風險。
Python 大量使用了異常模型,DB API 定義了若干標准異常,它們在調試應用程序中的問題時會非常有用。下面是一些標准異常,同時提供了原因類型的簡要說明:
- Warning — 數據在執行插入操作時被截斷,等等
- Error — 這里提到的除 Warning 外的所有異常的基類。
- InterfaceError — 數據庫接口而非數據庫本身故障(本例為 cx_Oracle 問題)
- DatabaseError — 嚴格意義上的數據庫問題
- DataError — 包含如下結果數據的問題除數為 0,值超出范圍等
- OperationalError — 與編程人員無關的數據庫錯誤:連接丟失、內存分配錯誤、事務處理錯誤等
- IntegrityError — 數據庫的關系完整性受到了影響,例如,外鍵約束失敗
- InternalError — 數據庫遇到內部錯誤,例如,游標無效、事務不同步
- ProgrammingError — 未找到表、SQL 語句中的語法錯誤、指定參數的數量錯誤等
- NotSupportedError — 調用的 API 部件並不存在
連接過程首先從連接對象開始,這是創建游標對象的基礎。除游標操作外,連接對象還使用 commit() 和 rollback() 方法對事務進行管理。執行 SQL 查詢、發出 DML/DCL 語句和獲取結果這些過程均受游標控制。
第一步:導入cx_Oracle ,建立連接
>>> import cx_Oracle >>> db = cx_Oracle.connect('hr', 'hrpwd', 'localhost:1521/XE') >>> db1 = cx_Oracle.connect('hr/hrpwd@localhost:1521/XE') >>> dsn_tns = cx_Oracle.makedsn('localhost', 1521, 'XE') >>> print dsn_tns (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SID=XE))) >>> db2 = cx_Oracle.connect('hr', 'hrpwd', dsn_tns)
# 通過客戶端連接oracle
connection = cx_Oracle.connect('test/test@ORCL')
第二步:建立 Cursor 光標,查詢
您可以使用連接對象的 cursor() 方法定義任意數量的游標。簡單的程序使用一個游標就可以了,該游標可以一再地重復使用。但較大的項目可能要求幾個不同的游標。
>>> cursor = db.cursor()
應用程序邏輯通常需要明確區分針對數據庫發出的語句的各個處理階段。這有助於更好地理解性能瓶頸並編寫更快且經過優化的代碼。語句處理分三個階段:
- 分析(可選)
- cx_Oracle.Cursor.parse([statement])
實際上並不需要調用,因為在執行階段會自動分析 SQL 語句。該方法可以用於在執行語句前對其進行驗證。當這類語句中檢測出錯誤時,會引發 DatabaseError 異常,相應的錯誤消息通常可能是“ORA-00900:invalid SQL statement, ORA-01031:insufficient privileges or ORA-00921:unexpected end of SQL command.”
- cx_Oracle.Cursor.parse([statement])
- 執行
- cx_Oracle.Cursor.execute(statement, [parameters], **keyword_parameters)
此方法可以接受單個參數 — 一條 SQL 語句 — 直接針對數據庫來運行。通過 parameters 或 keyword_parameters 參數賦值的綁定變量可以指定為字典、序列或一組關鍵字參數。如果已經提供了字典或關鍵字參數,那么這些值將與名稱綁定。如果給出的是序列,將根據這些值的位置對它們進行解析。如果是查詢操作,此方法返回一個變量對象列表;如果不是,則返回 None。 - cx_Oracle.Cursor.executemany(statement, parameters)
對於批量插入尤其有用,因為它可以將所需的 Oracle 執行操作的數量限制為僅一個。有關如何使用該方法的詳細信息,請參見下面的“一次多行”部分。
- cx_Oracle.Cursor.execute(statement, [parameters], **keyword_parameters)
- 獲取(可選)— 僅用於查詢(因為 DDL 和 DCL 語句不返回結果)。在不執行查詢的游標上,這些方法將引發 InterfaceError 異常。
- cx_Oracle.Cursor.fetchall()
以字節組列表形式獲取結果集中的所有剩余行。如果沒有剩余的行,它返回一個空白列表。獲取操作可以通過設置游標的 arraysize 屬性進行調整,該屬性可設置在每個底層請求中從數據庫中返回的行數。arraysize 的設置越高,需要在網絡中往返傳輸的次數越少。arraysize 的默認值為 1。 - cx_Oracle.Cursor.fetchmany([rows_no])
獲取數據庫中接下來的 rows_no 行。如果該參數未指定,該方法獲取的行數是 arraysize 的數量。如果 rows_no 大於獲取到的行的數目,該方法獲取的行數是剩余的行數。 - cx_Oracle.Cursor.fetchone()
從數據庫中獲取單個字節組,如果沒有剩余行,則返回 none。
- cx_Oracle.Cursor.fetchall()
在繼續了解游標示例前,請先了解 pprint 模塊的 pprint 函數。它用於以清晰、可讀的形式輸出 Python 數據結構。
# 獲得游標對象 cursor = connection.cursor () try: # 解析sql語句 cursor.parse("select * dual") # 捕獲SQL異常 except cx_Oracle.DatabaseError as e: print(e) # ORA-00923: 未找到要求的 FROM 關鍵字 # 執行sql 語句 cursor.execute ("select * from dual") # 提取一條數據,返回一個元祖 row = cursor.fetchone() pprint(row) # ('X',)
數據類型
在獲取階段,基本的 Oracle 數據類型會映射到它們在 Python 中的等同數據類型中。cx_Oracle 維護一個單獨的、有助於這一轉換的數據類型集合。Oracle - cx_Oracle - Python 映射為

查詢列字段信息
# 查詢列字段信息 column_data_types = cursor.execute('SELECT * FROM python_modules') pprint(column_data_types.description) # [('MODULE_NAME', <class 'cx_Oracle.STRING'>, 50, 50, None, None, 0), # ('FILE_PATH', <class 'cx_Oracle.STRING'>, 300, 300, None, None, 0)]
綁定變量模式
正如 Oracle 大師 Tom Kyte 介紹的那樣,綁定變量是數據庫開發的核心原則。它們不僅使程序運行更快,同時可以防范 SQL 注入攻擊。
按名稱傳遞綁定變量要求執行方法的 parameters 參數是一個字典或一組關鍵字參數。下面的 query1 和 query2 是等同的: >>> named_params = {'dept_id':50, 'sal':1000} >>> query1 = cursor.execute('SELECT * FROM employees WHERE department_id=:dept_id AND salary>:sal', named_params) >>> query2 = cursor.execute('SELECT * FROM employees WHERE department_id=:dept_id AND salary>:sal', dept_id=50, sal=1000) 在使用已命名的綁定變量時,您可以使用游標的 bindnames() 方法檢查目前已指定的綁定變量: >>> print cursor.bindnames() ['DEPT_ID', 'SAL'] # 綁定變量模式查詢 named_params = {'MODULE_NAME': 'cx_Oracle'} cursor.execute('SELECT * FROM python_modules where MODULE_NAME =:MODULE_NAME',named_params) # 在使用已命名的綁定變量時,您可以使用游標的 bindnames() 方法檢查目前已指定的綁定變量: print(cursor.bindnames()) pprint(cursor.fetchone()) # ('cx_Oracle', # 'C:\\Program ' # 'Files\\Python36\\lib\\site-packages\\cx_Oracle.cp36-win_amd64.pyd') # 在綁定時,您可以首先准備該語句,然后利用改變的參數執行 None。 # 根據綁定變量時准備一個語句即足夠這一原則, # Oracle 將如同在上例中一樣對其進行處理。准備好的語句可執行任意次。 cursor.prepare('SELECT * FROM python_modules where MODULE_NAME =:MODULE_NAME') cursor.execute(None, named_params) pprint(cursor.fetchone()) # ('cx_Oracle', # 'C:\\Program ' # 'Files\\Python36\\lib\\site-packages\\cx_Oracle.cp36-win_amd64.pyd')
一次多行
大型的插入操作不需求多次的單獨插入,這是因為 Python 通過 cx_Oracle.Cursor.executemany 方法完全支持一次插入多行。
限制執行操作的數量極大地改善了程序性能,因此在編寫存在大量插入操作的應用程序時應首先考慮這一功能。
我們首先為 Python 模塊列表創建一個表,這次直接從 Python 開始。您將在以后刪除該表。
import cx_Oracle # 用於以清晰、可讀的形式輸出 Python 數據結構 from pprint import pprint from sys import modules # 通過客戶端連接oracle connection = cx_Oracle.connect('test/test@testDB') print(connection.version) # 獲得游標對象 cursor = connection.cursor () try: # 解析sql語句 cursor.parse("select * dual") # 捕獲SQL異常 except cx_Oracle.DatabaseError as e: print(e) # ORA-00923: 未找到要求的 FROM 關鍵字 # 執行sql 語句 cursor.execute ("select * from dual") # 提取一條數據,返回一個元祖 row = cursor.fetchone() pprint(row) # ('X',) create_table = """ CREATE TABLE python_modules ( module_name VARCHAR2(50) NOT NULL, file_path VARCHAR2(300) NOT NULL ) """ # 執行創建表 create_flag = cursor.execute(create_table) # 添加模塊信息 M = [] for m_name, m_info in modules.items(): try: M.append((m_name, m_info.__file__)) except AttributeError: pass print(len(M)) insert_sql = "INSERT INTO python_modules(module_name, file_path) VALUES (:1, :2)" # 在prepare之后,你再去execute的時候,就不用寫上sql語句參數了 cursor.prepare(insert_sql) cursor.executemany(None, M) # 注意,第一個參數是None connection.commit() # 提交 # 查詢 r = cursor.execute("SELECT COUNT(*) FROM python_modules") pprint(cursor.fetchone()) # 查詢列字段信息 column_data_types = cursor.execute('SELECT * FROM python_modules') pprint(column_data_types.description) # [('MODULE_NAME', <class 'cx_Oracle.STRING'>, 50, 50, None, None, 0), # ('FILE_PATH', <class 'cx_Oracle.STRING'>, 300, 300, None, None, 0)] # 取10條記錄信息 pprint(len(cursor.fetchmany(10))) # 10 # 取之后所有記錄信息,不包括前10條 pprint(len(cursor.fetchall())) # 41 # 綁定變量模式查詢 named_params = {'MODULE_NAME': 'cx_Oracle'} cursor.execute('SELECT * FROM python_modules where MODULE_NAME =:MODULE_NAME',named_params) # 在使用已命名的綁定變量時,您可以使用游標的 bindnames() 方法檢查目前已指定的綁定變量: print(cursor.bindnames()) pprint(cursor.fetchone()) # ('cx_Oracle', # 'C:\\Program ' # 'Files\\Python36\\lib\\site-packages\\cx_Oracle.cp36-win_amd64.pyd') # 在綁定時,您可以首先准備該語句,然后利用改變的參數執行 None。 # 根據綁定變量時准備一個語句即足夠這一原則, # Oracle 將如同在上例中一樣對其進行處理。准備好的語句可執行任意次。 cursor.prepare('SELECT * FROM python_modules where MODULE_NAME =:MODULE_NAME') cursor.execute(None, named_params) pprint(cursor.fetchone()) # ('cx_Oracle', # 'C:\\Program ' # 'Files\\Python36\\lib\\site-packages\\cx_Oracle.cp36-win_amd64.pyd') # 刪除python_modules cursor.execute("DROP TABLE python_modules PURGE") # 關閉游標 cursor.close() # 關閉連接 connection.close () # BLOB & CLOB 格式的創建: # # binary_content = cursor.var(cx_Oracle.BLOB) # binary_content.setvalue(0, content)
