如何使用协会表,in子句和子查询查询sqlalchemy?

发布于 2025-02-11 10:35:09 字数 1311 浏览 2 评论 0 原文

我有一个课程表和一张学生表定义为

class Course(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200))
    tutor = db.Column(db.Integer, db.ForeignKey("tutor.id"))
    students = db.relationship("Student", secondary=association_table)


class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    email = db.Column(db.String(50))
    courses = db.relationship("Course", secondary=association_table)

与他们之间的许多关系,我创建了一个相关的表,

association_table = db.Table(
    "association",
    db.Model.metadata,
    db.Column("course_id", db.ForeignKey("course.id")),
    db.Column("student_id", db.ForeignKey("student.id")))

我想查询并获得特定学生所学的所有课程的结果。 SQL查询就像

SELECT * FROM course WHERE course.id IN (SELECT course_id FROM association WHERE student_id = 2)

我该如何使用SQLalchemy这样做?

目前,我的众多失败尝试的尝试之一是

query_ = self.session.query(Course)
query2 = self.session.query(association_table.course_id).all().filter_by(student_id=view_kwargs.get('student_id'))
query_ = query_.filter(Course.id.in_(query2)).all()

,当我使用Postman的API调用它时,我会得到这个。

AttributeError: 'Table' object has no attribute 'course_id'

I have a course table and a student table defined as

class Course(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200))
    tutor = db.Column(db.Integer, db.ForeignKey("tutor.id"))
    students = db.relationship("Student", secondary=association_table)


class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    email = db.Column(db.String(50))
    courses = db.relationship("Course", secondary=association_table)

and for a many to many relationship between them, I have created an associated table

association_table = db.Table(
    "association",
    db.Model.metadata,
    db.Column("course_id", db.ForeignKey("course.id")),
    db.Column("student_id", db.ForeignKey("student.id")))

I would like to query and get results of all courses taken by a particular student.
The SQL query would be like

SELECT * FROM course WHERE course.id IN (SELECT course_id FROM association WHERE student_id = 2)

How do I do this using sqlalchemy?

One of my many failed attempts to do this is

query_ = self.session.query(Course)
query2 = self.session.query(association_table.course_id).all().filter_by(student_id=view_kwargs.get('student_id'))
query_ = query_.filter(Course.id.in_(query2)).all()

At present, I'm getting this when I'm calling this using API from Postman.

AttributeError: 'Table' object has no attribute 'course_id'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冰雪梦之恋 2025-02-18 10:35:09

带有子选项的子句中的不是最优雅的(至少在过去,也不是执行查询的最佳方法)。

为了使用 JOIN 具有绝对相同结果的子句,请尝试下面的查询,这很简洁:

q = session.query(Course).filter(Course.students.any(Student.id == 2))

并将产生以下 sql

SELECT course.id,
       course.name
FROM course
WHERE EXISTS
    (SELECT 1
     FROM association,
          student
     WHERE course.id = association.course_id
       AND student.id = association.student_id
       AND student.id = ?)

但是,避免在 student 表格,以下更明确的查询将产生相同的结果:

q = (
    session
    .query(Course)
    .join(
        association_table, 
        (Course.id == association_table.c.course_id) & (association_table.c.student_id == 2),
    )
)

这将导致 sql 与以下相似:

SELECT  course.id,
        course.name
FROM    course
   JOIN association
     ON course.id = association.course_id
    AND association.student_id = ?

The IN clause with sub-select is not the most elegant (and at least in the past, also not the most optimal way to execute the query).

In order to use JOIN clause with absolutely the same result please try the query below which is very succinct:

q = session.query(Course).filter(Course.students.any(Student.id == 2))

and will produce following SQL:

SELECT course.id,
       course.name
FROM course
WHERE EXISTS
    (SELECT 1
     FROM association,
          student
     WHERE course.id = association.course_id
       AND student.id = association.student_id
       AND student.id = ?)

However, to avoid joining on the student table alltogether, the below more explicit query will result in the same outcome:

q = (
    session
    .query(Course)
    .join(
        association_table, 
        (Course.id == association_table.c.course_id) & (association_table.c.student_id == 2),
    )
)

which will result in the SQL similar to below:

SELECT  course.id,
        course.name
FROM    course
   JOIN association
     ON course.id = association.course_id
    AND association.student_id = ?
中二柚 2025-02-18 10:35:09

更新:我找到了一个可行的解决方案,实际上很简单。
就像:

session.query(Course).join(association_table).filter_by(student_id=view_kwargs["student_id"])

Update: I have found a solution that works and which is quite simple actually.
It goes like:

session.query(Course).join(association_table).filter_by(student_id=view_kwargs["student_id"])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文