使用SQLAlchemy连接到Oracle数据库

31

我能够成功地连接到一个SQLite数据库,并使用以下命令集访问特定的表:

from sqlalchemy import create_engine, MetaData, Table, and_
from sqlalchemy.sql import select
from pandas import DataFrame 

db = create_engine('sqlite:///path\\database.db')
metadata = MetaData(db)
table = Table('table name', metadata, autoload=True)

我能够使用 cx_Oracle 从 Oracle 数据库中获取数据。
但是,当我尝试在 SQLAlchemy 中连接到 Oracle 数据库时,出现了以下错误:

NoSuchTableError: <table name>

我使用了以下命令:
db = create_engine('oracle://username:password@hostname:1521/instance name', echo='debug')
md = MetaData(bind=db)
t = Table('table name', md, autoload=True, schema='schema name')

当我使用以下命令时:
t= Table('table name', md, autoload=True, oracle_resolve_synonyms=True)

我遇到了以下错误:

断言错误:模式中存在多个可见表,必须指定所有者

您能否解释一下我出了什么问题?


1
尝试传递 username."table name" 而不是 table name。我猜在其他架构中有另一个同名的表,这个用户也可以访问。 - webknjaz -- Слава Україні
6个回答

29

你不再需要导入cx_Oracle模块,较新版本的sqlalchemy模块会调用函数cx_Oracle.makedsn(),请看下面的示例:

from sqlalchemy.engine import create_engine

DIALECT = 'oracle'
SQL_DRIVER = 'cx_oracle'
USERNAME = 'your_username' #enter your username
PASSWORD = 'your_password' #enter your password
HOST = 'subdomain.domain.tld' #enter the oracle db host url
PORT = 1521 # enter the oracle port number
SERVICE = 'your_oracle_service_name' # enter the oracle db service name
ENGINE_PATH_WIN_AUTH = DIALECT + '+' + SQL_DRIVER + '://' + USERNAME + ':' + PASSWORD +'@' + HOST + ':' + str(PORT) + '/?service_name=' + SERVICE

engine = create_engine(ENGINE_PATH_WIN_AUTH)


#test query
import pandas as pd
test_df = pd.read_sql_query('SELECT * FROM global_name', engine)

2
你有没有想过为什么会一直出现错误,例如:“NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:oracle.cx_oracle”? - Konstantin
@Konstantin 你在使用虚拟环境吗? 我建议你安装cx_oracle以确保正常运行: python -m pip install cx_Oracle --upgrade - Luis Arteaga
我在使用这个方法时遇到了错误。这是Oracle最近更改的内容吗?在他们的博客中,他们只展示了一种需要wallet.sso文件的方法。 - Ricardo Sampaio
@RicardoSampaio,您能发布一下错误信息吗?还有您尝试访问的Oracle数据库版本是多少?我目前只使用Athena和MS SQL进行工作。所以我不确定如何重现它,但让我试试。 - Luis Arteaga

17
from sqlalchemy import create_engine
import cx_Oracle

host=hostname
port=port
sid='sid'
user='username'
password='password'
sid = cx_Oracle.makedsn(host, port, sid=sid)

cstr = 'oracle://{user}:{password}@{sid}'.format(
    user=user,
    password=password,
    sid=sid
)

engine =  create_engine(
    cstr,
    convert_unicode=False,
    pool_recycle=10,
    pool_size=50,
    echo=True
)

result = engine.execute('select * from TABLE')

for row in result:
    print row

这对我有用。连接对象也可以像这样创建

conn = engine.connect()
conn.close()

这将使您能够关闭连接。即使您在本地端口到远程数据库有一个隧道,这也可以工作。


2
我更喜欢使用 sqlalchemy.engine.url.URL("oracle", user, password, sid) 来构建连接字符串,而不是像 cstr 中那样直接使用连接字符串。 - aturegano

8

假设您的计算机上安装了Oracle客户端,并且有有效的tnsnames.ora文件,以下是我的解决方案:

from sqlalchemy import create_engine
import pandas as pd 
engine = create_engine('oracle://myusername:mypassword@SID')
con = engine.connect()
outpt = con.execute("SELECT * FROM YOUR_TABLE")
df = pd.DataFrame(outpt.fetchall())
df.columns = outpt.keys()
print(df.head())
con.close() 

1
连接Oracle时,无需使用tnsnames.ora文件,也不需要sqlalchemy。您可以轻松地使用LDAP、OUD、OID等进行连接。 - user9074332

2

1

当没有tnsnames.ora文件时,这对我很有效。

user = 'system'
pwd = 'oracle'
dsn = cx_Oracle.makedsn(
    '192.168.1.105', 49161,
    # service_name='your_service_name_if_any'
)
ora_engine = create_engine(f'oracle+cx_oracle://{user}:{pwd}@{dsn}', echo=True)
ora_engine.connect()

0

这是 @mkarun2 答案的稍微优化版本。

先决条件:

  • 安装以下软件包:

    sudo apt install libaio1

  • 下载 Oracle InstantClient 库

  • 创建符号链接:

    ln -s libclntsh.so.21.1 libclntsh.so

  • 像这样运行应用程序:

    export LD_LIBRARY_PATH=oracle-instantclient/instantclient_21_1 python main.py

这里是 main.py

import cx_Oracle
import sqlalchemy as sa


# Use your config
username = 'username'
password = 'security'
hostname = 'localhost'
service_name = 'Xal' or None
port = '1521'


# Tell cx_Oracle where to find the libraries. Optional.
cx_Oracle.init_oracle_client(lib_dir='oracle-instantclient/instantclient_21_1')


# Connection string
oracle_connection_string_fmt = (
    'oracle+cx_oracle://{username}:{password}@' +
    cx_Oracle.makedsn('{hostname}', '{port}', service_name='{service_name}')
)
url = oracle_connection_string_fmt.format(
    username=username, password=password, 
    hostname=hostname, port=port, 
    service_name=service_name,
)

# Create SqlAlchemy Engine
engine: sa.engine.Engine = sa.create_engine(url, echo=True)

以下是如何进行第一次查询的方法:

res: sa.engine.cursor.LegacyCursorResult = engine.execute("SELECT * FROM tablename")
for row in res:
    print(row)

请注意查询语句末尾没有分号; ;) Oracle 不喜欢分号。

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