我该如何从Python中访问Oracle?

40

我该如何在Python中访问Oracle数据库?我已经下载了cx_Oracle的msi安装程序,但是Python无法导入该库。

我收到以下错误:

import cx_Oracle

Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    import cx_Oracle
ImportError: DLL load failed: The specified module could not be found.

我将非常感谢任何帮助。


4
你下载的是哪个cx_Oracle?有许多选择。另外,你使用的Python版本、Oracle版本和操作系统是哪个? - Bill the Lizard
cx_Oracle-5.0.2-10g.win32-py26 - user425194
1
听起来好像没有被提取到Python用于查找模块的PATH中。您是否尝试使用easy_install安装它而不是显式地安装(可能缺少其他依赖项)? - JulesLt
这个特定的错误意味着 Oracle 客户端 OCI DDLs 是为不同平台编译的。32 位 vs 64 位或 Intel vs AMD。 - Alex B
10个回答

38

这是对我有用的方法。 我使用的Python和Oracle版本与您略有不同,但相同的方法适用。只需确保cx_Oracle二进制安装程序版本与您的Oracle客户端和Python版本匹配。

我的版本:

  • Python 2.7
  • Oracle Instant Client 11G R2
  • cx_Oracle 5.0.4(Unicode,Python 2.7,Oracle 11G)
  • Windows XP SP3

步骤:

  1. 下载Oracle Instant Client软件包。 我使用的是instantclient-basic-win32-11.2.0.1.0.zip。 将其解压缩到C:\ your \ path \ to \ instantclient_11_2中
  2. 下载并运行cx_Oracle二进制安装程序。 我使用的是cx_Oracle-5.0.4-11g-unicode.win32-py2.7.msi。我为所有用户安装了它,并将其指向了它在注册表中找到的Python 2.7位置。
  3. 通过批处理脚本或任何在应用程序上下文中有意义的机制设置ORACLE_HOME和PATH环境变量,使其指向Oracle Instant Client目录。 请参见下面的oracle_python.bat源。 我确定一定有更优雅的解决方案,但我想尽可能限制我的系统范围内更改。 确保将目标Oracle Instant Client目录放在PATH的开头(或至少在任何其他Oracle客户端目录之前)。 现在,我只是在命令行中运行oracle_python.bat,在运行需要cx_Oracle的程序之前。
  4. 运行regedit并检查是否在\ HKEY_LOCAL_MACHINE \ SOFTWARE \ ORACLE下设置了一个NLS_LANG键。 如果有,请重命名该键(我将其更改为NLS_LANG_OLD)或取消设置。此键仅应用于Oracle 7客户端的默认NLS_LANG值,因此可以安全地删除它,除非您还在其他位置使用Oracle 7客户端。 像往常一样,在进行更改之前,请务必备份注册表。
  5. 现在,您应该能够在Python程序中导入cx_Oracle。请参见下面的oracle_test.py源代码。请注意,我必须将连接和SQL字符串设置为Unicode,以适应我的版本cx_Oracle。

源代码:oracle_python.bat

@echo off
set ORACLE_HOME=C:\your\path\to\instantclient_11_2
set PATH=%ORACLE_HOME%;%PATH%

来源:oracle_test.py

import cx_Oracle

conn_str = u'user/password@host:port/service'
conn = cx_Oracle.connect(conn_str)
c = conn.cursor()
c.execute(u'select your_col_1, your_col_2 from your_table')
for row in c:
    print row[0], "-", row[1]
conn.close()

可能存在的问题:

  • "ORA-12705: 无法访问 NLS 数据文件或指定了无效的环境" - 在我进行 NLS_LANG 注册表更改之前,我遇到过这个问题。
  • "TypeError:第一个参数必须是 unicode,而不是 str" - 如果您需要将连接字符串设置为 Unicode。
  • "TypeError:期望 None 或者一个字符串" - 如果您需要将 SQL 字符串设置为 Unicode。
  • "ImportError:DLL 加载失败:找不到指定的程序。" - 可能表示 cx_Oracle 找不到适当的 Oracle 客户端 DLL。

有人知道只要所有版本号和平台都对齐,这是否适用于其他版本(例如3.4?和64位)吗? - Nate Anderson
1
@TheRedPea 这对于我来说在3.5版本和64位上都有效。 - Honinbo Shusaku
我仍在努力解决ImportError: DLL load failed: The specified procedure could not be found.这个问题,当我尝试导入cx_Oracle库的时候。 - Akshay
感谢详细的笔记,非常有帮助!我的理解是,在安装cx_oracle并连接到数据库之前,我需要先安装Oracle客户端。我正在尝试从我的计算机连接到我们公司集群中的Oracle数据库,但无法安装cx_oracle,出现以下错误消息:distutils.errors.DistutilsSetupError: 无法找到Oracle软件安装。 - Abhi
2
我真的需要Oracle客户端才能使其工作吗?难道不是直接使用JDBC连接就可以了吗?谢谢。 - Alex Pi

14

以下是我的代码示例,它展示了如何使用字典来使用查询参数。该代码在Python 3.6上运行:

import cx_Oracle

CONN_INFO = {
    'host': 'xxx.xx.xxx.x',
    'port': 12345,
    'user': 'SOME_SCHEMA',
    'psw': 'SECRETE',
    'service': 'service.server.com'
}

CONN_STR = '{user}/{psw}@{host}:{port}/{service}'.format(**CONN_INFO)

QUERY = '''
    SELECT
        *
    FROM
        USER
    WHERE
        NAME = :name
'''


class DB:
    def __init__(self):
        self.conn = cx_Oracle.connect(CONN_STR)

    def query(self, query, params=None):
        cursor = self.conn.cursor()
        result = cursor.execute(query, params).fetchall()
        cursor.close()
        return result


db = DB()
result = db.query(QUERY, {'name': 'happy'})

14

根据您拥有的服务名称SID,您可以使用以下任何一种方法。

使用SID:

import cx_Oracle
dsn_tns = cx_Oracle.makedsn('server', 'port', 'sid')
conn = cx_Oracle.connect(user='username', password='password', dsn=dsn_tns)
c = conn.cursor()
c.execute('select count(*) from TABLE_NAME')
for row in c:
   print(row)
conn.close()

或者

使用服务名称:

import cx_Oracle
dsn_tns = cx_Oracle.makedsn('server', 'port', service_name='service_name')
conn = cx_Oracle.connect(user='username', password='password', dsn=dsn_tns)
c = conn.cursor()
c.execute('select count(*) from TABLE_NAME')
for row in c:
   print(row)
conn.close()

5
import cx_Oracle
   dsn_tns = cx_Oracle.makedsn('host', 'port', service_name='give service name') 
   conn = cx_Oracle.connect(user='username', password='password', dsn=dsn_tns) 
   c = conn.cursor()
   c.execute('select count(*) from schema.table_name')
for row in c:
   print row
conn.close()

注意:

  1. 在 (dsn_tns) 中,如果需要,在任何参数前面放置 'r' 以解决任何特殊字符的问题,例如 '\'

  2. 在 (conn) 中,如果需要,在任何参数前面放置 'r' 以解决任何特殊字符的问题,例如 '\'. 例如,如果您的用户名包含 '\', 您需要在用户名前面放置 'r':user=r'用户名' 或 password=r'密码'

  3. 如果要将查询跨多行展开,请使用三重引号。


4
请注意,如果您正在使用 pandas,可以按以下方式访问它:

请注意,如果您正在使用 pandas,可以按以下方式访问它:

import pandas as pd
import cx_Oracle
conn= cx_Oracle.connect('username/pwd@host:port/service_name')
try:
    query = '''
         SELECT * from dual
             '''
    df = pd.read_sql(con = conn, sql = query)
finally:
    conn.close()
df.head()

3

除了Oracle即时客户端,您可能还需要安装Oracle ODAC组件并将其路径放入系统路径中。Cx_Oracle似乎需要访问与之一起安装的oci.dll文件。

还要检查您获取的版本是否正确(32位或64位),以匹配您的:python、cx_Oracle和即时客户端版本。


2
import cx_Oracle 
from sshtunnel import SSHTunnelForwarder

# remote server variables
remote_ip_address = "<PUBLIC_IP_ADDRESS_OF_DB_SERVER>"
remote_os_username = "<OS_USERNAME>"
ssh_private_key = "<PATH_TO_PRIVATE_KEY>"

# Oracle database variables
database_username = "<DATABASE_USER>"
database_password = "<DATABASE_USER_PASSWORD>"
database_server_sid = "<ORACLE_SID>"

def server_connection():

    server = SSHTunnelForwarder(
             remote_ip_address,
             ssh_username=remote_os_username,
             ssh_password=ssh_private_key,
             remote_bind_address=('localhost', 1521) # default Oracle DB port
    )
    return server

def database_connection():

    data_source_name = cx_Oracle.makedsn("localhost",
                                         server.local_bind_port,
                                         service_name=database_server_sid)

    connection = cx_Oracle.connect(database_username,
                                   database_password,
                                   data_source_name, 
                                   mode=cx_Oracle.SYSDBA) # If logging in with SYSDBA privs,
                                                          # leave out if not.
    return connection

def database_execute():

    connection = database_connection()

    cursor = connection.cursor()
    
    for row in cursor.execute("SELECT * FROM HELLO_WORLD_TABLE"):
        print(row)
    
if __name__ == '__main__':

    server = server_connection()
    server.start()                      # start remote server connection

    connection = database_connection()  # create Oracle database connection

    database_execute()                  # execute query

    connection.close()                  # close Oracle database connection
    server.stop()                       # close remote server connection

如果您通过堡垒隧道访问Oracle数据库,您只需要修改以下代码片段:
def server_connection():

server = SSHTunnelForwarder(
         remote_ip_address, # public IP of bastion server
         ssh_username=remote_os_username,
         ssh_password=ssh_private_key,
         remote_bind_address=('localhost', 1521),
         local_bind_address=('0.0.0.0', 3333) # Suppose local bind is '3333'
)
return server

2
除了 cx_Oracle 之外,您还需要安装 Oracle 客户端库并正确设置路径,以便 cx_Oracle 能够找到它 - 尝试在“Dependency Walker”中打开 cx_Oracle DLL (http://www.dependencywalker.com/),以查看缺少的 DLL 文件是什么。

2
如果你正在使用virtualenv,那么使用安装程序获取驱动程序就不是一件简单的事情。这时,你可以按照Devon所述进行安装。然后,将cx_Oracle.pyd和cx_Oracle-XXX.egg-info文件夹从Python\Lib\site-packages复制到虚拟环境的Lib\site-packages中。当然,在这里,架构和版本也很重要。

2

确保以下两点,它应该可以正常工作:

  1. Python、Oracle instantclient 和 cx_Oracle 都是 32 位的。
  2. 设置环境变量。

在 Windows 上修复此问题就像魔术一样简单。


那不是故意的,不确定它是怎么出现的。 - Venu Murthy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接