简体   繁体   English

SQLAlchemy:使用两个MySQL模式中的表进行查询

[英]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. 我必须对恰好分布在同一MySQL实例中两个不同模式中的表进行一些查询。 Using SQL, this is easy, just prefixing the table name with the schema name (assume a and be are the schema names): 使用SQL,这很容易,只需在表名前加上模式名即可(假设a和是模式名):

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. 在SQLAlchemy中,似乎可以使用两个引擎来使用它。 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. 当我执行q(例如q.all())时,它将失败。 "print q" shows a query with no schema names: “ print q”显示没有模式名称的查询:

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: 顺便说一句,我发现通过添加table_args,例如:

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... 但是想知道为什么其他代码没有...此外,在声明表的类时我没有模式名称,这意味着无论如何我都无法使用table_args技巧...

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. 我没有发现为什么该代码不起作用,我倾向于认为这是SQLAlchemy中的错误。 However, I've found a way of making a similar code work. 但是,我发现了一种使类似代码工作的方法。 It finally relies on using __table_args__ to define the schema. 最后,它依赖于使用__table_args__定义架构。 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. 这为名称为“ tablename”的表创建了一个类(名称为“ name”),但如果指定,则包括模式名称。

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. 如预期的那样,其中包括架构名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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