python连接oracle-从编码到版本不兼容等问题

一、前情提要

从分析需求(提出假设)-数据获取-数据处理-数据统计分析( 机器学习 )-输出结果(假设验证)整个数据分析工作流程中,虽然数据获取还未接触到数据分析最为核心的内容,但却是整个工作中最为基础的一步,如果缺少这一步,后续的处理和统计分析均无从下手。
数据获取,从文件类型作为区分点,目前至少有以下三种方式:

  1. 数据库,常见的数据获取方式;
  2. excel、csv等可直接通过文件打开和存储数据,但由于无法存储大批量数据以及查询统计效率较低等问题,在常规的批量数据分析中无法适用;
  3. 网络爬虫获取的数据源,虽有接触,但本文暂不讨论。

本文主要讨论从数据库中获取数据的方式,虽然可直接在数据库工具中用sql语句进行数据查询与导出,但鉴于复杂的多维度的统计以及数据库工具鸡肋的导出功能,因此本文选用python来连接oracle数据库。
可在实际连接使用中会出现诸如编码、oracle客户端不存在、python版本与数据库版本不兼容等问题,本文在借鉴前人的经验,记录这些问题的解决方案,以供参考。
笔者电脑安装环境与使用工具如下:

  1. 电脑系统,Windows7 - 专业版 - 64位
  2. python3.6.1 - 64位
  3. pycharm17.3 - 64位
  4. navicat premium11.0.17 - 64位

二、问题提要

经查阅资料,发现python需要借助cx_Oracle第三方库来连接oracle数据库,因此有以下步骤:

  1. 调出cmd窗口,输入 pip install cx_Oracle ,显示成功安装 cx_Oracle第三方库;
  2. 在pycharm新建一个py文件,输入以下内容:
    import cx_Oracle as oracle
    conn = oracle.connect('username', 'password', 'ip:port/sid')

    (1)username,数据库账户名
    (2)password,数据库账户密码
    (3)ip,数据库的ip地址
    (4)port,数据库端口
    (5)sid,数据库服务名
  3. print("oracle版本:", conn.version),用来测试是否连接成功

运行py文件后,脚本抛出以下异常
UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 82-83: invalid continuation byte
下面会开始讨论如何解决类似编码问题。

三、编码问题解决思路

先从数据获取的方式介绍常见的编码问题:

  1. 数据库,常出现数据库编码与python系统编码不一致,如我之前常用python连接mysql就曾遇过这个问题,需按以下设置:
    (1)pymysql第三方库的连接语句中有参数可以设置数据库连接的编码为utf-8;
    (2)设置mysql数据库的编码为utf-8;
    (3)python系统编码设置为utf-8;
  2. excel、csv文件
    (1)一般excel文件的读取都不会存在编码问题,如果出现编码问题,则需要查看源文件的编码是否和python系统编码一致;
    (2)csv文件,则需通过以下语句以固定编码打开文件
    pandas.read_csv(open(filepath, 'r', encoding='utf-8'))
  3. 爬虫数据,可获取url下的所有源代码后进行解码,具体语句为
    urllib.request.urlopen(url).read().decode("utf-8","ignore")

本文需要解决的就是第一种情况,python连接数据库时出现的编码问题。

  1. 从源头出发,猜测是部分字符串编码与其他不一致而导致的编码问题,因此有尝试将连接语句拆分为:
    (1)dsn = oracle.makedsn(ip, port, sid)
    (2)conn = oracle.connect( 'username', 'password',dsn)
    会发现在包含账号密码的第二个语句中抛出同样的异常。
    此时会进一步猜测是否账号密码的编码有问题,因此有尝试用encode('utf-8')的方法来将字符串转化为utf-8的编码,可是还是出现同样的编码异常。
    原本按照encode('utf-8')的方法处理后的字符串应该可以解决类似的编码问题,但目前却还未解决。
    因此可以猜测该异常并非是简单的编码问题,可是笔者还是不死心地换了一个账号密码,最后结果还是出现同样的异常。

  2. 如果并非是抛出异常的语句本身存在编码问题,那是否是与mysql数据库一样,存在数据库编码与python系统编码不一致的情况。
    可在查阅相关资料的时候,发现普遍是在连接数据库成功之后再查询数据的时候才出现编码问题,此时的解决方案,就是在一开始连接的时候就设置数据库环境编码,即增加语句
    os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
    类似的编码还有几个,即便抛开该解决方案不适用于目前的编码问题,用不同编码轮流尝试一次也都无法解决所出现的编码异常。
    此时则需要重新了解oracle数据库本身编码的设置情况,但笔者原本就没安装oracle数据库客户端,加上由于之前使用python连接mysql的时候,是有安装mysql数据库客户端,暂时猜测是否存在缺少oracle客户端的原因。

  3. 于是笔者着手开始下载了一个2.8G的oracle数据库客户端并安装成功。
    由于平时都是用navicat来连接oracle进行使用,同时python作为连接介质,并非是在客户端连接数据库的基础上再进行连接,因此没有必要摸索如何用oracle客户端连接其他数据库,就直接运行一开始的py文件。
    此时发现python抛出与之前不一样的异常:
    cx_Oracle.DatabaseError: DPI-1050: Oracle Client library must be at version 11.2 or higher
    很明显,就是提醒笔者电脑安装的oracle数据库客户端需要在11.2版本以上,但笔者是下载安装的12c版本的客户端,应该不存在版本老的问题,下面将开始讨论如何解决这个问题。

四、版本问题解决思路

由于安装的oracle版本是12c,并不存在低于oracle11.2版本的问题,因此查阅相关资料,发现该异常也有可能是因为python所安装的cx_Oracle第三方库版本与oracle版本不一致所引起的。
那问题就在于如何匹配cx_Oracle版本和oracle版本,由于较少资料讲到不同版本匹配的情况,仅零星资料讲到某个版本可匹配,笔者就抱着尝试的心态开始重新安装,具体步骤如下:

  1. 配置64位oracle11g即时客户端,主要是减少安装客户端的繁琐,或者区别于已安装的数据库版本;
    (1)网址:http://www.oracle.com/technetwork/topics/winx64soft-089540.html
    (2)下载 instantclient-basic-windows.x64-11.2.0.4.0.zip,按照自身电脑系统情况对应下载
    (3)根据个人习惯解压文件到固定路径,本文是’D:/instantclient/’

  2. 安装cx_Oracle,原本笔者是系统直接pip install安装,并未有选择性版本下载安装,此处也是为了保证版本一致
    (1)网址:https://pypi.python.org/pypi/cx_Oracle/6.0rc1
    (2)下载 cx_Oracle-6.0rc1-cp36-cp36m-win_amd64.whl,同样安装自身电脑系统对应下载
    (3)进入CMD窗口,并cd到文件所在目录,输入
    pip install cx_Oracle-6.0rc1-cp36-cp36m-win_amd64.whl

  3. 修改原py文件为:

import os 
import cx_Oracle as oracle
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'  ##保证编码一致
os.environ['path'] =  'D:/instantclient/'  ##使用即时客户端避免版本不兼容
conn = oracle.connect('username', 'password', 'ip:port/sid')
print("oracle版本:", conn.version)

此时会返回对应的oracle版本,因此已经成功连接oracle数据,可以执行下一步的sql语句,注意,返回的oracle版本为即时客户端的版本,而非电脑实际安装的客户端版本。

五、结语

本文能解决连接oracle数据库最为关键的一点在于找到 cx_Oracle-6.0rc1 和 oracle- 11.2.0.4.0能搭配使用,否则在重复尝试多个oracle版本和cx_Oracle版本搭配组合,所耗费的时间和人力都较多;
同时还有一个关键点,就是如何从编码问题,一步一步拆解及定位到版本不兼容问题;
中间还会遇到环境变量设置问题等问题,可以通过强行定义环境路径的方法解决;
也许笔者所遇到的情况与各位的略有不同,还望有所取舍和理解,有任何疑问,还希望能多交流;
下面还得感谢解决问题过程中所查阅的相关资料的作者。

参考资料:
http://blog.csdn.net/longlongValue/article/details/70792910
http://www.imooc.com/article/18964
http://blog.csdn.net/d12531256442/article/details/78076454?locationNum=6&fps=1

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页