在SQLAlchemy中,为什么在映射任意选择时我必须使用select构造别名?

时间:2013-02-24 02:29:00

标签: python sql sqlalchemy

我尝试复制文档regarding mapping models to arbitrary tables中的代码,但是我收到以下错误:

sqlalchemy.exc.InvalidRequestError: When mapping against a select() construct, map against an alias() of the construct instead.This because several databases don't allow a SELECT from a subquery that does not have an alias.

以下是我实现代码示例的方法。

from sqlalchemy import (
    select, func,
    Table, Column,
    Integer, ForeignKey,
    MetaData,
)

from sqlalchemy.ext.declarative import declarative_base

metadata = MetaData()
Base = declarative_base()

customers = Table('customer', metadata,
                  Column('id', Integer, primary_key=True),
                  )

orders = Table('order', metadata,
               Column('id', Integer, primary_key=True),
               Column('price', Integer),
               Column('customer_id', Integer, ForeignKey('customer.id')),
               )

subq = select([
            func.count(orders.c.id).label('order_count'),
            func.max(orders.c.price).label('highest_order'),
            orders.c.customer_id
            ]).group_by(orders.c.customer_id).alias()

customer_select = select([customers,subq]).\
            where(customers.c.id==subq.c.customer_id)

class Customer(Base):
    __table__ = customer_select

我可以使用以下方法完成这项工作:

class Customer(Base):
    __table__ = customer_select.alias()

不幸的是,这会在子选择中创建所有查询,这非常慢。

有没有办法将模型映射到任意选择?这是文档错误 - 来自文档的代码示例对我不起作用(在sqlalchemy == 0.8.0b2或0.7.10中)

1 个答案:

答案 0 :(得分:5)

如果一个子查询变得“过于缓慢”,这可能意味着你正在使用MySQL,正如我所指出的elsewhere具有非常不可接受的子查询性能。

select的映射基本上需要该语句,因此它的内部结构不会向外泄漏到使用它的上下文中,因此select()结构本身不需要是突变。

考虑你是否要像这样映射到SELECT:

SELECT id, name FROM table WHERE id = 5

现在假设你要从这个的映射中选择:

ma = aliased(Mapping)
query(Mapping).join(ma, Mapping.name == ma.name)

没有你的映射选择是一个别名,SQLAlchemy必须修改你的select(),这意味着它必须挖掘它并完全理解它的几何,这可能非常复杂(考虑它是否有LIMIT,ORDER BY ,GROUP BY,聚合等):

SELECT id, name FROM table 
 JOIN (SELECT id, name FROM table) as anon_1 ON table.name = anon_1.name 
 WHERE table.id = 5

然而,当它是自包含的时,SQLAlchemy可以保持对select()的结构一无所知,并像其他任何表一样使用它:

SELECT id, name FROM (SELECT id, name FROM table WHERE id = 5) as a1 
JOIN (SELECT id, name FROM table WHERE id = 5) as a2 ON a1.name = a2.name

实际上,映射到SELECT语句是一种罕见的用例,因为Query构造通常足够灵活,可以执行您需要的任何模式。 SQLAlchemy的早期版本将mapper()作为主要查询对象,在内部我们以这种方式利用mapper()的灵活性(特别是在连接继承中),但显式方法不是经常需要。

  

这是文档错误 - 来自文档的代码示例对我不起作用(在sqlalchemy == 0.8.0b2或0.7.10中)

感谢您指出这一点。我已经纠正了这个例子并添加了一个huge note来阻止整体练习,因为它没有太多用处(我知道这是因为我从来没有使用它)。