2017-09-26 2 views
0

Ich habe zwei Tabellen:Filter Eltern nach den Kindern zählen einige Kriterien zu respektieren

class Parent(Base): 
    __tablename__ = 'parents' 
    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 
    min_quantity = sqlalchemy.Column(sqlalchemy.Integer, default=0, nullable=False) 
    children = sqlalchemy.orm.relationship('Child', backref=sqlalchemy.orm.backref('parent') 

class Child(Base): 
    __tablename__ = 'children' 
    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) 
    expiration_date = sqlalchemy.Column(sqlalchemy.Date) 
    parent_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey('parents.id')) 

Was ist der einfachste Weg, nur übergeordnete Objekte auszuwählen, die mindestens min_quantity Kinder mit einem expiration_date < datetime.today haben() ?

konnte ich alle Eltern-Objekte abfragen und führen Sie dann eine Liste Verständnis:

parents = session.query(Parent).all() 
ok_parents = [parent for parent in parents if len([child for child in parent.children if child.expiration_date < datetime.today()]) > parent.min_quantity] 

Aber es fühlt sich nicht wie wirklich effizienten Code.

Ich nehme an, dass ich das in nur einer Abfrage mit den guten Optionen tun kann, und ich vermute, dass ich having() in meiner Abfrage verwenden muss, aber da meine Kenntnisse von sqlachemy (und SQL im Allgemeinen) noch begrenzt sind, Ich habe es nicht geschafft, dieses Problem zu lösen.

Also grundsätzlich bin ich offen für jeden Vorschlag.

Antwort

0

Sie haben Recht, dass Sie eine HAVING-Klausel verwenden könnten. Darüber hinaus könnten Sie zum Beispiel Abfrage Eltern mit Kindern verbunden sind, filtern diejenigen, die durch das Ablaufdatum Gruppe von Eltern-ID, und filtern Sie die Gruppen, die durch Anzahl der Zeilen pro Gruppe in Bezug Menge auf min:

ok_parents = session.query(Parent).\ 
    join(Child).\ 
    filter(Child.expiration_date < datetime.today()).\ 
    group_by(Parent.id).\ 
    having(func.count(1) > Parent.min_quantity).\ 
    all() 

eine Einschränkung in der Obige Abfrage ist, dass ein Elternteil ohne Kinder aufgrund des inneren Joins kein Ergebnis sein kann. Um dies zu umgehen, verwenden Sie outerjoin(Child) und filtern die resultierenden Zeilen, indem Sie entweder kein Kind (Child.id.is_(None)) oder das Ablaufdatum haben.

Verwandte Themen