2017-08-20 2 views
1

Das ist mein SQLAlchemy AbfragecodeWie begrenzt man N Ergebnisse pro `group_by` in SQLAlchemy/Postgres?

medium_contact_id_subq = (g.session.query(distinct(func.unnest(FUContact.medium_contact_id_lis))).filter(FUContact._id.in_(contact_id_lis))).subquery() 
q = (g.session.query(FUMessage). 
     filter(FUMessage.fu_medium_contact_id.in_(medium_contact_id_subq)) 
     .order_by(desc(FUMessage.timestamp_utc)) 
     ) 

I FUMessage von medium_contact_id mit N Ergebnisse gruppiert begrenzen möchten.


Als Abhilfe können, das ist meine aktuelle hässlich und nicht optimierten Code:

medium_contact_id_lis = (g.session.query(distinct(func.unnest(FUContact.medium_contact_id_lis))).filter(FUContact._id.in_(contact_id_lis))).all() 
    q = None 
    for medium_contact_id_tup in medium_contact_id_lis: 
     medium_contact_id = medium_contact_id_tup[0] 
     if q is None: 
      q = (g.session.query(FUMessage) 
       .filter(FUMessage.fu_medium_contact_id == medium_contact_id) 
       .limit(MESSAGE_LIMIT) 
       ) 
     else: 
      subq = (g.session.query(FUMessage) 
       .filter(FUMessage.fu_medium_contact_id == medium_contact_id) 
       .limit(MESSAGE_LIMIT) 
       ) 
      q = q.union(subq) 
    q = q.order_by(desc(FUMessage.timestamp_utc)) 
+0

Da die Unterabfragen, die die Vereinigung bilden nicht bestellen Vor dem Limit sind Ihre Ergebnisse unbestimmt. –

Antwort

3

Ein Weg, Top-N Zeilen abzurufen pro Gruppe eine Fensterfunktion wie rank() oder row_number() zu verwenden, ist in Wählen Sie einen Subselect mit der erforderlichen Gruppierung und Reihenfolge aus und filtern Sie danach in der umschließenden Auswahl. Für N = 1 können Sie die DISTINCT ON ... ORDER BY Kombination in Postgresql verwenden.

Annahme, dass auf SQLAlchemy ist einfach Funktionselement des over() Methode unter Verwendung eines Fensters Ausdruck zu erzeugen:

medium_contact_id_subq = g.session.query(
     func.unnest(FUContact.medium_contact_id_lis).distinct()).\ 
    filter(FUContact._id.in_(contact_id_lis)).\ 
    subquery() 

# Perform required filtering in the subquery. Choose a suitable ordering, 
# or you'll get indeterminate results. 
subq = g.session.query(
     FUMessage, 
     func.row_number().over(
      partition_by=FUMessage.fu_medium_contact_id, 
      order_by=FUMessage.timestamp_utc).label('n')).\ 
    filter(FUMessage.fu_medium_contact_id.in_(medium_contact_id_subq)).\ 
    subquery() 

fumessage_alias = aliased(FUMessage, subq) 

# row_number() counts up from 1, so include rows with a row num 
# less than or equal to limit 
q = g.session.query(fumessage_alias).\ 
    filter(subq.c.n <= MESSAGE_LIMIT) 
+0

brilliant, das hat funktioniert! – nubela

Verwandte Themen