【问题标题】:Can I run a query within a query using SQLAlchemy? [duplicate]我可以使用 SQLAlchemy 在查询中运行查询吗? [复制]
【发布时间】:2017-05-07 07:40:53
【问题描述】:

可以使用单个 SQLAlchemy session.query 完成以下 MySQL 查询还是必须运行第二个 session.query ?如果有,怎么会?

Select *, (select c from table2 where id = table1.id) as d from table1 where foo = x

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    你想要的是 SQLAlchemy 的 subquery 对象。本质上,您照常编写查询,但不是以.all().first() 结束查询(通常直接返回某种结果),而是以.subquery() 结束查询以返回子查询目的。子查询对象基本上生成嵌入在别名中的子查询 SQL,但不运行它。然后您可以在主查询中使用它,SQLAlchemy 将发出必要的 SQL 以在单个操作中执行查询和子查询。

    假设我们有以下student_scores 表:

    +------------+-------+-----+
    |    name    | score | age |
    +------------+-------+-----+
    | Xu Feng    |   95  |  25 |
    | John Smith |   88  |  26 |
    | Sarah Taft |   89  |  25 |
    | Ahmed Zaki |   86  |  26 |
    +------------+-------+-----|
    

    (忽略可怕的数据库设计)

    在此示例中,我们希望获得一个包含所有学生及其分数的结果集,并按年龄加入平均分数。在原始 SQL 中,我们会这样做:

      SELECT ss.name, ss.age, ss.score, sub.average
        FROM student_scores AS "ss"
        JOIN ( SELECT age, AVG(score) AS "average"
                 FROM student_scores
             GROUP BY age) AS "sub"
          ON ss.age = sub.age
    ORDER BY ss.score DESC
    

    结果应该是这样的:

    +------------+-------+-----+---------+
    |    name    | score | age | average |
    +------------+-------+-----+---------+
    | Xu Feng    |   95  |  25 |    92   |
    | John Smith |   88  |  26 |    87   |
    | Sarah Taft |   89  |  25 |    92   |
    | Ahmed Zaki |   86  |  26 |    87   |
    +------------+-------+-----|---------+
    

    在 SQLAlchemy 中,我们可以先自己定义子查询:

    from sqlalchemy.sql import func
    
    avg_scores = (
        session.query(
            func.avg(StudentScores.score).label('average'),
            StudentScores.age
        )
        .group_by(StudentScores.age)
        .subquery()
    )
    

    现在我们的子查询已定义,但实际上并没有向数据库发送任何语句。尽管如此,我们可以将子查询对象几乎视为另一个表,并编写我们的主查询:

    results = (
        session.query(StudentScores, avg_scores)
        .join(avg_scores, StudentScores.age == avg_scores.c.age)
        .order_by('score DESC').all()
    )
    

    现在才向数据库发出任何 SQL,我们得到的结果与原始子查询示例相同。

    话虽如此,您提供的示例实际上非常简单,根本不需要子查询。根据您的关系定义方式,SQLAlchemy 可以急切地加载相关对象,以便对象返回:

    results = session.query(Table1).filter(Table1.foo == 'x').all()
    

    将有权访问来自 Table2 的子(或父)记录,即使我们在这里没有要求它 - 因为直接在模型中定义的关系正在为我们处理。查看 SQLAlchemy 文档中的"Relationship Loading Techniques",了解有关其工作原理的更多信息。

    【讨论】:

    猜你喜欢
    • 2016-11-02
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多