繁体   English   中英

内部引用外部别名表的内部查询中的Sqlalchemy from_self

[英]Sqlalchemy from_self in an inner query referencing outer aliased table

我有这样的sqlalchemy查询:

E = aliased(Entity, name='e')
db.session.query(E) \
    .filter(E.user_id == user_id) \
    .filter(
        db.session.query(Entity) \
            .distinct(Entity.original_id) \
            .order_by(Entity.original_id, Entity.id.desc())
            .filter(Entity.ref_id == E.ref_id) \
            .from_self(Entity.flag) \
            .order_by(Entity.timestamp.desc()) \
            .limit(1).as_scalar()
    ) \
    .order_by(E.timestamp) \
    .all()

它产生(大致)以下SQL:

SELECT *
FROM entity AS e
WHERE e.user_id = 1 AND (
    SELECT anon_1.entity_flag AS flag
    FROM (
        SELECT DISTINCT ON (entity.original_id)
            entity.flag AS entity_flag, entity.timestamp AS entity_timestamp
        FROM entity, entity AS e # THIS "entity AS e" SHOULD NOT BE HERE
        WHERE
            entity.ref_id = e.ref_id
            ORDER BY entity.original_id, entity.id DESC
    ) AS anon_1
    ORDER BY anon_1.entity_timestamp
    LIMIT 1
) ORDER BY e.timestamp;

因为它以某种方式将entity AS e添加到内部查询FROM子句中,所以它导致WHERE entity.ref_id = e.ref_id不能按WHERE entity.ref_id = e.ref_id引用外部表。

为什么将此无关entity AS e添加到内部FROM子句中,以及如何克服它?

可能是您发现了Query.from_self()的局限性:

对于简单的过滤器和排序,自动别名功能仅在有限的方式下起作用。 更雄心勃勃的构造(例如在联接中引用实体)应该更喜欢使用显Query.subquery()查询对象,通常使用Query.subquery()方法来产生显Query.subquery()查询对象。 始终通过查看SQL来测试查询的结构,以确保特定的结构符合预期!

通常,SQLAlchemy的“自动关联”只考虑FROM对象来进行直接封闭查询的关联,如果需要更深层次的嵌套,则必须使用显式关联。

另一方面,这对您没有帮助。 添加到通话Query.correlate()通过的边界不破Query.from_self()由于某种原因,尽管使用它们一起在文档中提到,即使:

在使用Query.from_self()或将Query.subquery()返回的子查询嵌入到另一个select()构造中时,相关参数会生效。

一种解决方案是使用显式子查询:

In [65]: sq = session.query(Entity.flag, Entity.timestamp).\
    ...:     distinct(Entity.original_id).\
    ...:     order_by(Entity.original_id, Entity.id.desc()).\
    ...:     filter(Entity.ref_id == E.ref_id).\
    ...:     correlate(E).\
    ...:     subquery()

In [66]: q = session.query(E).\
    ...:     filter(E.user_id == 123).\
    ...:     filter(session.query(sq.c.flag).
    ...:            order_by(sq.c.timestamp.desc()).
    ...:            limit(1).
    ...:            as_scalar()).\
    ...:     order_by(E.timestamp)
    ...:            

In [67]: print(q.statement.compile(dialect=postgresql.dialect()))
SELECT e.id, e.ref_id, e.timestamp, e.original_id, e.user_id, e.flag 
FROM entity AS e 
WHERE e.user_id = %(user_id_1)s AND (SELECT anon_1.flag 
FROM (SELECT DISTINCT ON (entity.original_id) entity.flag AS flag, entity.timestamp AS timestamp 
FROM entity 
WHERE entity.ref_id = e.ref_id ORDER BY entity.original_id, entity.id DESC) AS anon_1 ORDER BY anon_1.timestamp DESC 
 LIMIT %(param_1)s) ORDER BY e.timestamp

暂无
暂无

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

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