38

如何从 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

10 回答 10

37

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

我的版本:

  • 蟒蛇 2.7
  • Oracle 即时客户端 11G R2
  • cx_Oracle 5.0.4(Unicode、Python 2.7、Oracle 11G)
  • 视窗 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 客户端目录之前)。现在,我只做命令行的事情,所以在运行任何需要 cx_Oracle 的程序之前,我只在 shell 中运行 oracle_python.bat。
  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 源代码。请注意,对于我的 cx_Oracle 版本,我必须将连接和 SQL 字符串设置为 Unicode。

来源: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: argument 1 must be unicode, not str” - 如果您需要将连接字符串设置为 Unicode。
  • “TypeError: Expecting None or a string” - 如果您需要将 SQL 字符串设置为 Unicode。
  • “ImportError:DLL 加载失败:找不到指定的过程。” - 可能表明 cx_Oracle 找不到合适的 Oracle 客户端 DLL。
于 2011-01-24T16:33:17.343 回答
14

您可以根据Service NameSID您拥有的任何方式使用以下任何一种方式。

使用 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()
于 2018-11-10T11:44:02.907 回答
13

这是我的代码的样子。它还显示了如何使用字典使用查询参数的示例。它适用于使用 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'})
于 2018-03-23T10:44:12.030 回答
4
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'User Name' or password=r'password'

  3. 如果您想将查询分布在多行中,请使用三引号。

于 2018-11-05T20:34:21.930 回答
4

请注意,如果您使用的是 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()
于 2018-08-15T02:48:22.577 回答
3

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

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

于 2012-03-16T10:48:41.727 回答
2

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

于 2010-08-19T18:54:57.090 回答
2

如果您使用的是 virtualenv,那么使用安装程序获取驱动程序并非易事。然后你可以做什么:按照 Devon 的描述安装它。然后将 cx_Oracle.pyd 和 cx_Oracle-XXX.egg-info 文件夹从 Python\Lib\site-packages 复制到虚拟环境中的 Lib\site-packages 中。当然,在这里,架构和版本也很重要。

于 2015-04-02T08:43:49.650 回答
2

确保这两个,它应该工作: -

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

像魅力一样在 Windows 上修复了这个问题。

于 2013-04-26T11:53:04.810 回答
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
于 2021-08-25T21:42:35.927 回答