我可以使用 SQLAlchemy 在查询中运行查询吗?

Ada*_*m P 2 python sqlalchemy

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

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

dav*_*ing 5

你想要的是 SQLAlchemy 的subquery对象。本质上,您可以像往常一样编写查询,但不是以.all()or结束查询.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 |
+------------+-------+-----|
Run Code Online (Sandbox Code Playgroud)

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

在这个例子中,我们想要得到一个包含所有学生及其分数的结果集,并按年龄加入平均分数。在原始 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
Run Code Online (Sandbox Code Playgroud)

结果应该是这样的:

+------------+-------+-----+---------+
|    name    | score | age | average |
+------------+-------+-----+---------+
| Xu Feng    |   95  |  25 |    92   |
| John Smith |   88  |  26 |    87   |
| Sarah Taft |   89  |  25 |    92   |
| Ahmed Zaki |   86  |  26 |    87   |
+------------+-------+-----|---------+
Run Code Online (Sandbox Code Playgroud)

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

from sqlalchemy.sql import func

avg_scores = (
    session.query(
        func.avg(StudentScores.score).label('average'),
        StudentScores.age
    )
    .group_by(StudentScores.age)
    .subquery()
)
Run Code Online (Sandbox Code Playgroud)

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

results = (
    session.query(StudentScores, avg_scores)
    .join(avg_scores, StudentScores.age == avg_scores.c.age)
    .order_by('score DESC').all()
)
Run Code Online (Sandbox Code Playgroud)

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

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

results = session.query(Table1).filter(Table1.foo == 'x').all()
Run Code Online (Sandbox Code Playgroud)

将可以访问 Table2 中的子(或父)记录,即使我们在这里没有要求它 - 因为直接在模型中定义的关系正在为我们处理。查看SQLAlchemy 文档中的“关系加载技术”以获取有关其工作原理的更多信息。