在sqlalchemy中强制内部联接与多对多关系

时间:2012-05-03 17:21:12

标签: python mysql sqlalchemy

我正在使用declarative_base()并尝试弄清楚在使用多对多关系时如何强制执行延迟内连接。

我在MySQL和InnoDB中有表定义了外键约束。

users: userid, name
permissions: permissionid, name
users_permissions: userid, permissionid

我正在使用metadata.reflect()来加载我的数据库。


class User_Perm(Base):
    __table__ = Base.metadata.tables['users_permissions']

class User(Base):
    __table__ = Base.metadata.tables['users']

    permissions = orm.relationship('Permission',
            secondary=User_Perm.__table__,
            order_by='Perm.name',
            innerjoin=True,
            lazy=True,
            )

class Permission(Base):
    __table__ = Base.metadata.tables['permissions']

每当我选择

u = Session().query(User).filter(User.name == 'myuser').first()
u.permissions

MySQL服务器收到的查询是:

SELECT permissions.permissionid AS permissions_permissionid,
     permissions.name AS permissions_name
FROM permissions, users_permissions 
WHERE ? = users_permissions.userid
    AND permissions.permissionid = users_permissions.permissionid
ORDER BY permissions.name

正如我们所看到的,FROM permissions, users_permissions不是内连接。我是否可以在不需要使用lazy=False的情况下强制执行此操作,因为如果我这样做,则级联效果将加载太多信息,因为permissions也与另一个表(示例中未提及)和users也与其他表相关(同样,在示例中未提及)。我想为我所有的课程使用相同的模板来建立关系。

编辑:上下文我正在尝试复制所有SQL查询以匹配当前系统中的查询。我正在尝试从oursql迁移到sqlalchemy orm

1 个答案:

答案 0 :(得分:3)

MySQL 进行内部联接;也就是说,您显示的查询是内部联接的一种实现。

来自docs

  

innerjoin = False - 当为True时,加入的eager加载将使用内部联接   连接相关表而不是外连接。目的   这个选项严格地说是性能之一,作为内部连接   通常比外连接表现更好。此标志可以设置为   当关系通过多对一使用引用对象时为True   不可为空的本地外键,或者引用时的外键   一对一或保证有一个或至少一个的集合   一个条目。

关键点是inner join vs. outer join。语法无关紧要。

请注意,您的查询可以使用具有完全相同含义的inner join句法形式转换为查询:

SELECT permissions.permissionid AS permissions_permissionid,
     permissions.name AS permissions_name
FROM permissions
INNER JOIN users_permissions 
    ON permissions.permissionid = users_permissions.permissionid
WHERE ? = users_permissions.userid
ORDER BY permissions.name

MySQL通常会为这两种表单生成相同的执行计划。