【问题标题】:SQLAlchemy: query using tables in two MySQL schemasSQLAlchemy:使用两个 MySQL 模式中的表进行查询
【发布时间】:2014-08-23 22:04:29
【问题描述】:

我必须对恰好分布在同一个 MySQL 实例中的两个不同模式中的表进行一些查询。使用 SQL,这很容易,只需在表名前加上模式名(假设 a 和 be 是模式名):

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

在 SQLAlchemy 中,这似乎可以使用两个引擎。在阅读文档之后,在我看来,以下代码应该可以工作(使用两个不同模式名称的棘手部分是 bingings):

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

但事实并非如此。当我执行 q(例如 q.all())时它失败了。 "print q" 显示一个没有模式名称的查询:

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

而不是我的预期:

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

我在这里错过了什么?

顺便说一句,我发现通过添加 table_args 例如在:

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

(对于两个表),它都有效。但是想知道为什么其他代码没有...此外,我在为表声明类时没有架构名称,这意味着我无论如何都不能使用 table_args 技巧...

所以,总结一下:如何使用来自两个模式的表进行查询,“好方法”,如果可能的话,我在声明表类时不需要包含名称,但稍后,当引擎和会话时有定义吗?

【问题讨论】:

    标签: python mysql sql database sqlalchemy


    【解决方案1】:

    我不知道为什么该代码不起作用,我倾向于认为这是 SQLAlchemy 中的一个错误。但是,我找到了一种使类似代码工作的方法。它最终依赖于使用__table_args__ 来定义模式。但由于直到运行时我才知道模式的名称,所以我使用以下函数动态定义表的类:

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

    这为名为“tablename”的表创建了一个类(名为“name”),但如果指定,则包括架构名称。

    使用此解决方案的代码与问题中的代码非常相似,如下所示:

    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
    

    现在,它会打印:

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

    其中包括架构名称,如预期的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-09
      • 2014-10-09
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多