36

I am able to successfully connect to a SQLite database and access a particular table using the set of commands below:

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)

I am able to fetch data from an Oracle database using cx_Oracle.

However, when I try to connect to an Oracle database in SQLAlchemy, I am getting the following error:

NoSuchTableError: <table name>

I have used the following commands:

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')

When I use the following command:

t= Table('table name', md, autoload=True, oracle_resolve_synonyms=True)

I get the following error:

AssertionError: There are multiple tables visible to the schema, you must specify owner

Can you please explain where exactly I am going wrong?

1
  • 1
    Try passing username."table name" instead of table name. I guess there's another table with the same name in other schema, which is accessible by this user as well. Commented Feb 12, 2015 at 17:28

7 Answers 7

33

You don't need to import cx_Oracle anymore. The newer version of the sqlalchemy module calls the function cx_Oracle.makedsn(). Have a look:

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)
Sign up to request clarification or add additional context in comments.

4 Comments

Any idea why I keep getting errors such as: "NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:oracle.cx_oracle"?
@Konstantin Are you using a virtual environment? I would install cx_oracle just to make sure: python -m pip install cx_Oracle --upgrade
I'm having errors using this method.. is it something they've changed recently in oracle? In their blog, they only show a method in which you need the wallet.sso file..
@RicardoSampaio could you post the error message, please. And the oracle db version you try to access? I am currently working only with Athena and MS SQL. So i am not sure how to reproduce it but let me try.
16
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

This worked for me. A connection object can also be created like

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

which will enable to close the connection. This works even if you have a tunnel to your remote DB from your local port.

1 Comment

Instead of using connection string as in cstr, I would prefer to build it from sqlalchemy.engine.url.URL("oracle", user, password, sid)
9

Assuming you have the Oracle client on your machine with a valid tnsnames.ora file, this works for me:

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 Comment

There is no sqlalchemy requirement for connecting to Oracle with tnsnames.ora. You can connect with LDAP, OUD, OID, etc just as easily.
3

"... if you already have a connection string that works with cx_Oracle":

import pandas as pd
from sqlalchemy import create_engine
import cx_Oracle

conn_factory = lambda: conn_factory = lambda: cx_Oracle.connect(user=dbuser, password=dbpass, dsn=dsn)

engine = create_engine(
    "oracle://", 
    creator=conn_factory
)

data = pd.read_sql("SELECT 1 FROM DUAL", engine)

https://gist.github.com/DGrady/7fb5c2214f247dcff2cb5dd99e231483?permalink_comment_id=4035380#gistcomment-4035380

Comments

1

This works for me, when there is no tnsnames.ora file.

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()

Comments

1

Using oracledb I first generate the DSN via the ConnectParams method. then I use that as the host with SQLAlchemy

import oracledb
import pandas as pd
from pandas import DataFrame
from sqlalchemy import create_engine, text
from sqlalchemy.engine import URL


def __get_dataframe(sql: str) -> DataFrame:
    cp = oracledb.ConnectParams(
        host="Server",
        port=1521,
        service_name="SID")

    connection_url = URL.create(
        "oracle+oracledb",
        host=cp.get_connect_string(),
        username="username",
        password="password",
    )
    with create_engine(connection_url).connect() as connection:
        data_frame = connection.execute(text(sql)).fetchall()

    return pd.DataFrame(data_frame)


results = __get_dataframe("SELECT 1 FROM DUAL")

1 Comment

0

Here's a slighty polished version of @mkarun2's answer.

Prerequisites:

  • Install packages:

    sudo apt install libaio1

  • Download Oracle InstantClient library

  • Make a symlink:

    ln -s libclntsh.so.21.1 libclntsh.so

  • Run the app like this:

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

Heres 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)

Here's how to make your first query:

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

notice that the query does not have ; at the end ;) Oracle does not like semicolons.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.