SQLAlchemy 根据另一个表中的值过滤表的最佳方法

Enr*_*ini 1 python sql sqlalchemy

如果我的问题很平庸,我提前道歉:我是 SQL 的初学者。

我想创建一个简单的数据库,有两个表:StudentsAnswers。基本上,每个学生将回答三个问题(每个问题可能的答案是TrueFalse),他的答案将存储在Answers表中。 Students可以有两个“经验”级别:“本科生”和“研究生”。获得“研究生”经验级别Answers所提供的所有内容的最佳方式是什么?Students

这就是我为StudentsAnswers表中的条目定义 SQLAlchemy 类的方式:

import random

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Date, Boolean, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship


db_uri = "sqlite:///simple_answers.db"
db_engine = create_engine(db_uri)
db_connect = db_engine.connect()

Session = sessionmaker()
Session.configure(bind=db_engine)
db_session = Session()


Base = declarative_base()    


class Student(Base):
    __tablename__ = "Students"
    
    id = Column(Integer, primary_key=True)
    experience = Column(String, nullable=False)

class Answer(Base):
    __tablename__ = "Answers"
    
    id = Column(Integer, primary_key=True)
    student_id = Column(Integer, ForeignKey("Students.id"), nullable=False)
    answer = Column(Boolean, nullable=False)


Base.metadata.create_all(db_connect)
Run Code Online (Sandbox Code Playgroud)

然后,我在数据库中插入一些随机条目:

categories_experience = ["Undergraduate", "Graduate"]
categories_answer = [True, False]

n_students = 20
n_answers_by_each_student = 3
random.seed(1)
for _ in range(n_students):
    student = Student(experience=random.choice(categories_experience))
    db_session.add(student)
    db_session.commit()
    
    answers = [Answer(student_id=student.id, answer=random.choice(categories_answer))
               for _ in range(n_answers_by_each_student)]
    db_session.add_all(answers)
    db_session.commit()
Run Code Online (Sandbox Code Playgroud)

然后,我获得Student.id所有“研究生”学生的:

ids_graduates = db_session.query(Student.id).filter(Student.experience == "Graduate").all()
ids_graduates = [result.id for result in ids_graduates]
Run Code Online (Sandbox Code Playgroud)

最后,我使用运算符Answers从“Graduate”中选择:Students.in_

answers_graduates = db_session.query(Answer).filter(Answer.student_id.in_(ids_graduates)).all()
Run Code Online (Sandbox Code Playgroud)

我手动检查了答案,它们是正确的。但是,由于我是 SQL 的初学者,我怀疑有一些更好的方法可以达到相同的结果。

有没有这样一种客观的“最佳”方式(更Pythonic,更高效......)?我想通过 SQLAlchemy 实现我的结果,可能使用 ORM 接口。

Enr*_*ini 12

当我问这个问题的时候,我很着急。从那时起,我就有时间研究SQLAlchemy ORM文档。有两种推荐的方法可以根据另一个表中的值过滤表。

第一种方法实际上与我最初尝试的非常相似:

query_graduates = (
    db_session
    .query(User.id)
    .filter(User.experience == "Graduate")
)
query_answers_graduates = (
    db_session
    .query(Answer)
    .filter(Answer.user_id.in_(query_graduates))
)
answers_graduates = query_answers_graduates.all()
Run Code Online (Sandbox Code Playgroud)

它使用.in_运算符,该运算符接受对象列表或另一个查询作为参数。

第二种方式使用.join方法:

query_answers_graduates = (
    db_session
    .query(Answer)
    .join(User)
    .filter(User.experience == "Graduate")
)
Run Code Online (Sandbox Code Playgroud)

第二种方法更简洁。我对两种解决方案进行了计时,第二种方法使用.join,速度稍快一些。