sqlalchemy 对复杂的连接进行聚合

问题描述 投票:0回答:1

对不好的标题表示歉意,因为除了我的 sql 技能之外,我不确定确切的问题是什么。

我有以下型号(为了清晰起见,进行了精简):

class Student (db.Model):
   id = db.Column(db.Integer, primary_key=True)
   good_behaviour_marks = db.Column(db.Integer)
   tests = db.relationship('Test', backref='student', lazy='dynamic', cascade='all, delete-orphan')

   @hybrid_property
   def total_marks(self):
      marks = self.good_behaviour_marks
      for test in tests:
          marks += tests.score
      return marks

class Test (db.Model):
   id = db.Column(db.Integer, primary_key=True)
   subject = db.Column(db.String)
   score = db.Column(db.Integer)
   student_id = db.Column(db.Integer, db.ForeignKey('Student.id'))

一个学生可以参加多个科目的考试。我想编写一个查询来获取所有参加数学测试的学生的总分总和。

示例:

Student1 -> id:1 good_behaviour_marks:5 tests:[Math:10, Science:20] total_marks: 50
Student2 -> id:2 good_behaviour_marks:2 tests:[Science:15, English:20] total_marks:37
Student3 -> id:3 good_behaviour_marks:4 tests:[Math:10, Spanish:10] total_marks:24

查询应返回 -> 50 + 24 = 74,这是以数学为科目之一的学生的总分之和。

我正在使用flask-sqlalchemy,如果有帮助的话。我对 sql 查询的结构有一些了解:

select sum(total_marks)
from (
   ( 
      select 
        id, total_marks
      from student
   ) a
   leftjoin
   (
      select
        student_id
      from test
      where subject=='Math'
   ) b
   on (a.id == b.student_id)
   group_by (id)
)

但我没有成功地将其转换为 sqlalchemy 查询。任何帮助将不胜感激。

python sql join sqlalchemy flask-sqlalchemy
1个回答
0
投票

您需要在学生和测试之间执行联接,过滤那些进行数学测试的学生,然后使用聚合函数对总分进行求和。像这样:

from sqlalchemy import func

# perform the join
students_with_math_tests = db.session.query(Student).join(
    Test, Test.student_id == Student.id
).filter(
    Test.subject == 'Math'
)

# calculate total marks
total_marks_sum = sum(student.total_marks for student in students_with_math_tests)

print(total_marks_sum)

这很简单,可能不适合大型数据集。 或者,您也可以直接在查询中处理总和:

result = db.session.query(
    func.sum(Student.good_behaviour_marks + func.coalesce(func.sum(Test.score), 0))
).join(
    Test, Test.student_id == Student.id
).filter(
    Test.subject == 'Math'
).group_by(
    Student.id
).all()

# since result will return a list of sums for each student, sum them up to get the total
total_marks_sum = sum(x[0] for x in result)

print(total_marks_sum)

这有点复杂,但应该更有效。希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.