简体   繁体   English

SQLAlchemy 没有在选择上正确构建 JOIN

[英]SQLAlchemy not building JOIN on select correctly

I'm trying to translate the following query into a SQLAlchemy ORM query:我正在尝试将以下查询转换为 SQLAlchemy ORM 查询:

SELECT applications.*, 
       appversions.version 
FROM   applications 
       JOIN appversions 
         ON appversions.id = (SELECT id 
                              FROM   appversions 
                              WHERE  appversions.app_id = applications.id 
                              ORDER  BY sort_ver DESC 
                              LIMIT  1) 

The model for the tables are as follows:表的模型如下:

Base = declarative_base()

class Application(Base):
    __tablename__ = 'applications'

    id       = Column(Integer, primary_key = True)
    group    = Column(Unicode(128))
    artifact = Column(Unicode(128))

    versions = relationship("AppVersion", backref = "application")

class AppVersion(Base):
    __tablename__ = 'versions'

    id        = Column(Integer, primary_key = True)
    app_id    = Column(Integer, ForeignKey('applications.id'))
    version   = Column(Unicode(64))
    sort_ver  = Column(Unicode(64))

And the query I've so far come up with is:到目前为止,我提出的查询是:

subquery = select([AppVersion.id]). \
                where(AppVersion.app_id == Application.id). \
                order_by(AppVersion.sort_ver). \
                limit(1). \
                alias()


query = session.query(Application). \
                join(AppVersion, AppVersion.id == subquery.c.id) \
                .all()

However, this is producing the following SQL statement and error:但是,这会产生以下 SQL 语句和错误:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such column: anon_1.id
[SQL: SELECT applications.id AS applications_id, applications."group" AS applications_group, applications.artifact AS applications_artifact
FROM applications JOIN versions ON versions.id = anon_1.id]

I have tried various different methods to produce the subquery and attempting to 'tack on' the sub-SELECT command, but without any positive impact.我尝试了各种不同的方法来生成子查询并尝试“附加”子 SELECT 命令,但没有任何积极影响。

Is there a way to coerce the SQLAlchemy query builder to correctly append the sub-SELECT?有没有办法强制 SQLAlchemy 查询构建器正确附加子 SELECT?

With thanks to @Ilja Everilä for the nudge in the right direction, the code to generate the correct query is:感谢@Ilja Everilä 在正确方向上的推动,生成正确查询的代码是:

subquery = select([AppVersion.id]). \
                where(AppVersion.app_id == Application.id). \
                order_by(AppVersion.sort_ver). \
                limit(1). \
                correlate(Application)

query = session.query(Application). \
                join(AppVersion, AppVersion.id == subquery) \
                .all()

The main change is to use the correlate() method, which alters how SQLAlchemy constructs the subquery.主要的变化是使用correlate()方法,它改变了 SQLAlchemy 构造子查询的方式。

To explain why this works requires some understanding of how SQL subqueries are categorised and handled.要解释为什么会这样,需要对 SQL 子查询的分类和处理方式有所了解。 The best explanation I have found is from https://www.geeksforgeeks.org/sql-correlated-subqueries/ :我找到的最好的解释来自https://www.geeksforgeeks.org/sql-correlated-subqueries/

With a normal nested subquery, the inner SELECT query runs first and executes once, returning values to be used by the main query.对于普通的嵌套子查询,内部 SELECT 查询首先运行并执行一次,返回主查询要使用的值。 A correlated subquery, however, executes once for each candidate row considered by the outer query.但是,相关子查询对外部查询考虑的每个候选行执行一次。 In other words, the inner query is driven by the outer query.换句话说,内部查询由外部查询驱动。

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

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