简体   繁体   中英

SQLAlchemy: query using tables in two MySQL schemas

I have to do some queries on tables that happen to be spread in two different schemas in the same MySQL instance. Using SQL, this is easy, just prefixing the table name with the schema name (assume a and be are the schema names):

SELECT upeople.id AS upeople_id 
FROM a.upeople JOIN b.changes ON upeople.id = changes.changed_by

In SQLAlchemy, it seems this can be used using two engines. And after reading documentation, it seems to me that the following code should work (the bingings doing the tricky part of using two different schema names):

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.query import Query

Base = declarative_base(cls=DeferredReflection)
BaseId = declarative_base(cls=DeferredReflection)

class Changes(Base):
    __tablename__ = 'changes'

class UPeople(BaseId):
    __tablename__ = 'upeople'

database='mysql://jgb:XXX@localhost/a'
id_database='mysql://jgb:XXX@localhost/b'

engine = create_engine(database)
id_engine = create_engine(id_database)
Base.prepare(engine)
BaseId.prepare(id_engine)
bindings = {Changes: engine,
            UPeople: id_engine}
Session = sessionmaker(binds=bindings)
session = Session()
q = session.query(UPeople.id).join(Changes,
                                   UPeople.id == Changes.changed_by)
print q

But it doesn't. When I execute q (eg q.all()) it fails. "print q" shows a query with no schema names:

SELECT upeople.id AS upeople_id 
FROM upeople JOIN changes ON upeople.id = changes.changed_by

instead of what I expected:

SELECT upeople.id AS upeople_id 
FROM a.upeople JOIN b.changes ON upeople.id = changes.changed_by

What am I missing here?

BTW, I have found that by adding table_args such as in:

class Changes(Base):
    __tablename__ = 'changes'
    __table_args__ = {'schema': 'a'}

(for both tables), it works. But wonder why the other code doesn't... In addition, I don't have the schema names at the moment of declaring the classes for the tables, with means I cannot use the table_args trick anyway...

So, summarizing: how to query using tables from two schemas, the "good way", and if possible in a way that I don't need to include the name when declaring Table classes, but later, when engines and session are defined?

I didn't find out why that code don't work, I'm tending to think it is a bug in SQLAlchemy. However, I've found a way of making a similar code work. It finally relies on using __table_args__ to define the schema. But since I don't have the name of the schema until runtime, I define the classes for the tables dynamically, using the following function:

def table_factory (name, tablename, schemaname):

   table_class = type(
        name,
        (Base,),
        dict (
            __tablename__ = tablename,
            __table_args__ = {'schema': schemaname}
            )
        )
    return table_class

This created a class (of name "name") for the table of name "tablename", but including the schema name if specified.

A code quite similar to that in the question, using this solution, is as follows:

Base = declarative_base()
database='mysql://jgb:XXX@localhost/'
Changes = table_factory (name = "Changes",
                         tablename = "changes",
                         schemaname = 'a')
UPeople = table_factory (name = "UPeople",
                         tablename = "upeople",
                         schemaname = 'b')
engine = create_engine(database)
Base.prepare(engine)
Session = sessionmaker(bind=engine)
session = Session()
q = session.query(UPeople.id).join(Changes,
                                   UPeople.id == Changes.changed_by)
print q

Now, it prints:

SELECT b.upeople.id AS b_upeople_id 
FROM b.upeople JOIN a.changes ON b.upeople.id = a.changes.changed_by

Which includes the schema names, as intended.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM