可以使用单个SQLAlchemy session.query完成以下MySQL查询,还是必须运行第二个session.query?如果是这样,怎么会这样?
从table1中选择*,(从table2中选择c,其中id = table1.id)为d,其中foo = x
答案 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",了解有关其工作原理的更多信息。