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

时间:2017-05-07 07:40:54

标签: python sqlalchemy

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

从table1中选择*,(从table2中选择c,其中id = table1.id)为d,其中foo = x

1 个答案:

答案 0 :(得分:3)

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

假设我们有以下.subquery()表:

student_scores

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

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

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

结果应该是这样的:

  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

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

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

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

from sqlalchemy.sql import func

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

现在只有SQL发布到数据库,我们得到与原始子查询示例相同的结果。

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

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

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