Python連接Oracle之環(huán)境配置、實(shí)例代碼及報(bào)錯(cuò)解決方法詳解
Oracle Client 安裝
1、環(huán)境
日期:2019年8月1日
公司已經(jīng)安裝好Oracle服務(wù)端
Windows版本:Windows10專業(yè)版
系統(tǒng)類型:64位操作系統(tǒng),基于x64的處理器
Python版本:Python 3.6.4 :: Anaconda, Inc.
2、下載網(wǎng)址
https://www.oracle.com/database/technologies/instant-client/downloads.html
3、解壓至目錄
解壓后(這里放D盤)
4、配置環(huán)境變量
控制面板\系統(tǒng)和安全\系統(tǒng) -> 高級(jí)系統(tǒng)設(shè)置 -> 環(huán)境變量
新建ORACLE_HOME,值為包解壓的路徑
編輯PATH,添加%ORACLE_HOME%
Navicat連接測(cè)試
cx_Oracle
安裝命令
conda install cx_Oracle
基礎(chǔ)代碼
import cx_Oracle def execute(query): db = cx_Oracle.connect('用戶名/密碼@IP/ServiceName') cursor = db.cursor() cursor.execute(query) result = cursor.fetchall() cursor.close() db.close() return result def commit(sql): db = cx_Oracle.connect('用戶名/密碼@IP/ServiceName') cursor = db.cursor() cursor.execute(sql) db.commit() cursor.close() db.close()
封裝成類
from cx_Oracle import Connection # conda install cx_Oracle from conf import CONN, Color class Oracle(Color): def __init__(self, conn=CONN): self.db = Connection(*conn, encoding='utf8') # 用戶名 密碼 IP/ServiceName self.cursor = self.db.cursor() def __del__(self): self.cursor.close() self.db.close() def commit(self, sql): try: self.cursor.execute(sql) self.db.commit() except Exception as e: self.red(e) def fetchall(self, query): self.cursor.execute(query) return self.cursor.fetchall() def fetchone(self, query, n=9999999): self.cursor.execute(query) for _ in range(n): one = self.cursor.fetchone() if one: yield one def fetchone_dt(self, query, n=9999999): self.cursor.execute(query) columns = [i[0] for i in self.cursor.description] length = len(columns) for _ in range(n): one = self.cursor.fetchone() # tuple yield {columns[i]: one[i] for i in range(length)} def read_clob(self, query): self.cursor.execute(query) one = self.cursor.fetchone() while one: try: yield one[0].read() except Exception as e: self.red(e) one = self.cursor.fetchone() def db2sheet(self, query, prefix): df = pd.read_sql_query(query, self.db) if 'url' in df.columns: df['url'] = "'" + df['url'] df.to_excel(prefix.replace('.xlsx', '')+'.xlsx', index=False) def db2sheets(self, queries, prefix): writer = pd.ExcelWriter(prefix.replace('.xlsx', '')+'.xlsx') for sheet_name, query in queries.items(): df = pd.read_sql_query(query, self.db) if 'url' in df.columns: df['url'] = "'" + df['url'] df.to_excel(writer, sheet_name=sheet_name, index=False) writer.save() def tb2sheet(self, table): sql = "SELECT * FROM " + table self.db2sheet(sql, table) def insert(self, dt, tb): for k, v in dt.items(): if isinstance(v, str): dt[k] = v.replace("'", '').strip() ls = [(k, v) for k, v in dt.items() if v is not None] sql = 'INSERT INTO %s (' % tb + ','.join(i[0] for i in ls) + \ ') VALUES (' + ','.join('%r' % i[1] for i in ls) + ')' self.commit(sql) def insert_clob(self, dt, tb, clob): for k, v in dt.items(): if isinstance(v, str): dt[k] = v.replace("'", '').strip() # 把超長文本保存在一個(gè)變量中 # declare = "DECLARE variate CLOB := '%s';\n" % dt[clob] join = lambda x: '||'.join("'%s'" % x[10922*i: 10922*(i+1)] for i in range(len(x)//10922+1)) # 32768//3 declare = "DECLARE variate CLOB := %s;\n" % join(dt[clob]) dt[clob] = 'variate' ls = [(k, v) for k, v in dt.items() if v is not None] sql = 'INSERT INTO %s (' % tb + ','.join(i[0] for i in ls) + ') VALUES (' +\ ','.join('%r' % i[1] for i in ls) + ');' sql = declare + 'BEGIN\n%s\nEND;' % sql.replace("'variate'", 'variate') self.commit(sql) def update(self, dt_update, dt_condition, table): sql = 'UPDATE %s SET ' % table + ','.join('%s=%r' % (k, v) for k, v in dt_update.items()) \ + ' WHERE ' + ' AND '.join('%s=%r' % (k, v) for k, v in dt_condition.items()) self.commit(sql) def truncate(self, tb): self.commit('truncate table ' + tb) db_read = Oracle() fetchall = db_read.fetchall fetchone = db_read.fetchone read_clob = db_read.read_clob if __name__ == '__main__': query = ''' '''.strip() for i in fetchone(query, 99): print(i)
conf
CONN = ('用戶名', '密碼', 'IP/ServiceName') conn = '用戶名/密碼@IP/ServiceName'
文本字符串查詢
class INSTR(Oracle): """文本字符串查詢""" def highlight_instr(self, table, field, keyword, clob=True): sql = "SELECT %s FROM %s WHERE INSTR(%s,'%s')>0" % (field, table, field, keyword) if clob: for i in self.read_clob(sql): self.highlight(i, keyword) else: for i, in self.fetchone(sql): self.highlight(i, keyword) def regexp_instr(self, table, field, pattern, regexp=True, clob=True): sql = "SELECT %s FROM %s WHERE INSTR(%s,'%s')>0" % (field, table, field, pattern) sql = sql.replace('INSTR', 'REGEXP_INSTR') if regexp else sql if clob: for i in self.read_clob(sql): yield i else: for i, in self.fetchone(sql): yield i
一個(gè)簡單的建表示例
-- 建表 CREATE TABLE table_name ( serial_number NUMBER(10), collect_date DATE, url VARCHAR2(255), long_text CLOB, price NUMBER(10)-- 若需要精確到小數(shù)點(diǎn)2位,按分存儲(chǔ),/100還原到元 ); -- 給表添加備注 COMMENT ON TABLE table_name IS '中文表名'; -- 給表字段添加備注 COMMENT ON COLUMN table_name.serial_number IS '編號(hào)'; COMMENT ON COLUMN table_name.collect_date IS '日期'; COMMENT ON COLUMN table_name.url IS 'URL'; COMMENT ON COLUMN table_name.long_text IS '長文本'; COMMENT ON COLUMN table_name.price IS '價(jià)錢'; -- 插入 INSERT INTO table_name(collect_date) VALUES (DATE'2019-08-23'); INSERT INTO table_name(long_text) VALUES ('a'); INSERT INTO table_name(long_text) VALUES ('b'); -- 查詢 SELECT * FROM table_name WHERE TO_CHAR(long_text) in ('a','b'); -- 查建表語句(表名大寫) SELECT dbms_metadata.get_ddl('TABLE','TABLE_NAME') FROM dual; -- 刪表 DROP TABLE table_name;
sqlalchemy
import os # 解決【UnicodeEncodeError: 'ascii' codec can't encode character】問題 os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.AL32UTF8' # os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' from cx_Oracle import makedsn from sqlalchemy import create_engine, Column, String, Integer from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker # 連接數(shù)據(jù)庫(ORA-12505: TNS:listener does not currently know of SID given in connect descriptor) ip = '' port = '' tnsname = '' # 實(shí)例名 uname = '' # 用戶名 pwd = '' # 密碼 dsnStr = makedsn(ip, port, service_name=tnsname) connect_str = "oracle://%s:%s@%s" % (uname, pwd, dsnStr) # 創(chuàng)建連接引擎,這個(gè)engine是lazy模式,直到第一次被使用才真實(shí)創(chuàng)建 engine = create_engine(connect_str, encoding='utf-8') # 創(chuàng)建對(duì)象的基類 Base = declarative_base() class Student(Base): # 表名 __tablename__ = 'student' # 表字段 sid = Column(String(20), primary_key=True) age = Column(Integer) # 建表(繼承Base的所有表) Base.metadata.create_all(bind=engine) # 使用ORM操作數(shù)據(jù)庫 Session = sessionmaker(bind=engine) # 創(chuàng)建ORM基類 session = Session() # 創(chuàng)建ORM對(duì)象 tb_obj = Student(sid='a6', age=18) # 創(chuàng)建表對(duì)象 session.add(tb_obj) # 添加到ORM對(duì)象(插入數(shù)據(jù)) session.commit() # 提交 session.close() # 關(guān)閉ORM對(duì)象 # 刪表(繼承Base的所有表) Base.metadata.drop_all(engine)
報(bào)錯(cuò)處理
DPI-1047: 64-bit Oracle Client library cannot be loaded
首先操作系統(tǒng)位數(shù)、python位數(shù)、cx_Oracle版本要對(duì)應(yīng)上;另外可能缺【Visual C++】
每次裝完后,要重啟pycharm和python
ORA-12170: TNS:Connect timeout occurred
打開終端ping一下
檢查【主機(jī)名或IP地址】、【服務(wù)名或SID】、【用戶名】和【密碼】是否填對(duì)
中文亂碼
encoding=‘utf8'
ORA-00972: identifier is too long
insert語句中出現(xiàn)'之類的字符
解決方法:將可能報(bào)錯(cuò)的字符替換掉
ORA-64203: Destination buffer too small to hold CLOB data after character set conversion.
select TO_CHAR(long_text) from table_name,目標(biāo)緩沖區(qū)太小,無法儲(chǔ)存CLOB轉(zhuǎn)換字符后的數(shù)據(jù)
解決方法:不在SQL用TO_CHAR,改在Python中用read(如上代碼所示)
ORA-01704: string literal too long
雖然CLOB可以保存長文本,但是SQL語句有長度限制
解決方法:把超長文本保存在一個(gè)變量中(如上代碼所示)
PLS-00172: string literal too long
字符串長度>32767(215-1)
解決方法:使用'||'來連接字符串(如上代碼所示)
ORA-00928: missing SELECT keyword
INSERT操作時(shí),表字段命名與數(shù)據(jù)庫內(nèi)置名稱沖突,如:ID、LEVEL、DATE等
解決方法:建立命名規(guī)范
cx_Oracle.DatabaseError: ORA-12505: TNS:listener does not currently know of SID given in connect descriptor
使用sqlalchemy時(shí)的報(bào)錯(cuò)
原因可能是目標(biāo)數(shù)據(jù)庫是集群部署的,可以咨詢一下DBA,或見上面代碼from cx_Oracle import makedsn
UnicodeEncodeError: 'ascii' codec can't encode character
使用sqlalchemy時(shí)的報(bào)錯(cuò),插入中文字符引起
解決方法是設(shè)置os.environ['NLS_LANG']
更多關(guān)于Python連接Oracle之環(huán)境配置、實(shí)例代碼及報(bào)錯(cuò)解決方法請(qǐng)查看下面的相關(guān)鏈接
相關(guān)文章
python2爬取百度貼吧指定關(guān)鍵字和圖片代碼實(shí)例
這篇文章主要介紹了python2爬取百度貼吧指定關(guān)鍵字和圖片代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08在Python中封裝GObject模塊進(jìn)行圖形化程序編程的教程
這篇文章主要介紹了在Python中封裝GObject模塊進(jìn)行圖形化程序編程的教程,本文來自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下2015-04-04Python中json格式數(shù)據(jù)的編碼與解碼方法詳解
這篇文章主要介紹了Python中json格式數(shù)據(jù)的編碼與解碼方法,詳細(xì)分析了Python針對(duì)json格式數(shù)據(jù)的編碼轉(zhuǎn)換操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07Pytorch實(shí)現(xiàn)張量的創(chuàng)建與使用方法
本文主要介紹了Pytorch實(shí)現(xiàn)張量創(chuàng)建使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08基于Python實(shí)現(xiàn)剪切板實(shí)時(shí)監(jiān)控方法解析
這篇文章主要介紹了基于Python實(shí)現(xiàn)剪切板實(shí)時(shí)監(jiān)控方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09Pytorch上下采樣函數(shù)之F.interpolate數(shù)組采樣操作詳解
最近用到了上采樣下采樣操作,pytorch中使用interpolate可以很輕松的完成,下面這篇文章主要給大家介紹了關(guān)于Pytorch上下采樣函數(shù)之F.interpolate數(shù)組采樣操作的相關(guān)資料,需要的朋友可以參考下2022-04-04Pyqt5 實(shí)現(xiàn)跳轉(zhuǎn)界面并關(guān)閉當(dāng)前界面的方法
今天小編就為大家分享一篇Pyqt5 實(shí)現(xiàn)跳轉(zhuǎn)界面并關(guān)閉當(dāng)前界面的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06