2016-07-10 11 views
0

Ich habe die folgenden Tabellen:SQLAlchemy subquery Vergleich

class Job(db.Model): 
    __tablename__ = 'jobs' 
    id = db.Column(db.Integer, primary_key=True) 


class Informant(db.Model): 
    __tablename__ = 'informants' 
    id = db.Column(db.Integer, primary_key=True) 
    job_id = db.Column(db.Integer, db.ForeignKey('jobs.id')) 
    max_students = db.Column(db.Integer)   


class Student(db.Model): 
    __tablename__ = 'students' 
    id = db.Column(db.Integer, primary_key=True) 


queues = db.Table('queues', 
        db.Column('student_id', db.Integer, db.ForeignKey('students.id')), 
        db.Column('job_id', db.Integer, db.ForeignKey('jobs.id')), 
        PrimaryKeyConstraint('student_id', 'job_id')) 

Jetzt brauche ich etwas zu erhalten, wie:

SELECT jobs.id 
FROM jobs 
WHERE (
    SELECT SUM(informants.max_students) 
    FROM informants 
    WHERE informants.job_id = jobs.id 
) <= (
    SELECT COUNT(1) 
    FROM queues 
    WHERE queues.job_id = jobs.id 
) 

Also im Grunde die Arbeitsplätze mit einer Menge von Studenten, die ich suchen, die das überschreiten maximale Kapazität, die Summe der zugehörigen Informantenkapazitäten. Gibt es einen sauberen Weg, dies in SQLAlchemy zu tun? Ich habe folgendes versucht:

db.session.query(Job.id).filter(\ 
    db.session.query(db.func.sum(Informant.max_students)). \ 
     filter(Informant.job_id == Job.id) <= \ 
    db.session.query(db.func.count(1)).select_from(queues). \ 
     filter(queues.c.job_id == Job.id)) 

Dies ergibt etwas wie SELECT jobs.id FROM jobs WHERE 0 = 1. Gibt es etwas, das ich vermisse, weil ich zuvor ähnliche Abfragen erfolgreich durchgeführt habe? Oder verwende ich besser db.engine.execute, um das rohe SQL auszuführen?

+0

Warum verschiebst du 'max_students' nicht nach Job? Die Abfrage wird danach viel einfacher. –

+0

Weil ein Informant die maximale Anzahl an Studenten wählt, die er bedienen möchte. Studenten sollten in eine Warteschlange gestellt werden (für neue Informanten mit derselben Aufgabe), wenn keine weiteren Informanten mit dem vollständigen Informantenjob verfügbar sind. Ich weiß, dass die Abfrage ziemlich komplex ist, vielleicht werde ich einfach ein Flag setzen, wenn ein Job für die Warteschlange geöffnet ist. Studenten wählen Informanten an erster Stelle und sie müssen wissen, ob ein Informant voll ist. Wenn dies der Fall ist, werden sie für den Job des Informanten in eine Warteschlange gestellt. – Y4sper

+0

Nun, was kommt als nächstes? Ich denke, dass Sie die Spalte "max_students" in "Jobs" Tabelle platzieren können. Wenn 'job_id' in 'informants' nicht eindeutig ist, können Sie sie in einer Zeile in der' jobs'-Tabelle zusammenfassen. Sie tun sowieso, aber jetzt - von 'SUM' in Ihre Abfrage. Ich sehe keine Notwendigkeit, "Informanten" zu sein. –

Antwort

0

Ich war nahe dran, die richtige Antwort zu haben. Das Stück, das fehlte, ist eine as_scalar-Methode für beide Unterabfragen. Die letzte Abfrage lautet also:

db.session.query(Job.id).filter(\ 
    db.session.query(db.func.sum(Informant.max_students)). \ 
     filter(Informant.job_id == Job.id).as_scalar() <= \ 
    db.session.query(db.func.count(1)).select_from(queues). \ 
     filter(queues.c.job_id == Job.id).as_scalar()) 
+0

Sie können Ihre eigene Antwort als die richtige Lösung markieren. – RazerM

+0

Ich muss noch 22 Stunden darauf warten ... – Y4sper