Here is my database model.
class Doctor(db.Model):
__tablename__ = 'doctor'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), nullable=False)
class Patient(db.Model):
__tablename__ = 'patient'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), nullable=False)
class Assignment(db.Model):
__tablename__ = 'assignment'
doctorid = db.Column(db.Integer, ForeignKey('doctor.id'),
unique=False, nullable=False, index=True, primary_key=True)
patientid = db.Column(db.Integer, ForeignKey('patient.id'),
unique=False, nullable=False, index=True, primary_key=True)
created = db.Column(db.DateTime(timezone=False),
server_default=db.func.now())
I would like to list all Doctors who has less than 3 (may be a user-specified N
) Patients assigned.
The assignment is recorded in the assignment
table using ForeignKey.
Note that some Doctors may have zero Patient assigned, they should also be included in the results.
I was thinking about something like sub-queries, GROUP BY or OUTER JOIN but I couldn't figure out how to put counting N
in them.
Also, I would like to further exclude all Doctors who are assigned with a certain Patient patientid = P1
from the results. Is this possible to be done in addition to the first (less then N
) condition?
CodePudding user response:
To count the number of assignments per doctor use GROUP BY and to select only groups, in this case doctors, meeting certain criteria use the HAVING clause. It is possible to deterministically select non aggregate columns from a group, if they are functionally dependent on the grouping, which is the case if grouping by primary key.
docs = db.session.query(Doctor).\
outerjoin(Assignment).\
group_by(Doctor.id).\
having(
db.func.count() < n,
db.func.count().filter(Assignment.patientid == p1) == 0).\
all()
If your DBMS does not support the aggregate FILTER clause used above to eliminate doctors assigned with patient P1, you can use an EXISTS subquery expression instead:
docs = db.session.query(Doctor).\
outerjoin(Assignment).\
filter(db.not_(db.session.query(Assignment).filter(
Assignment.patientid == p1,
Assignment.doctorid == Doctor.id).exists())).\
group_by(Doctor.id).\
having(db.func.count() < n).\
all()