2013-07-02 4 views
6

Ich versuche, die folgende SQL-Abfrage mit sqlalchemy ORM zu schreiben:Komplexe Abfrage (Subqueries, Fensterfunktionen) mit sqlalchemy

SELECT * FROM 
    (SELECT *, row_number() OVER(w) 
    FROM (select distinct on (grandma_id, author_id) * from contents) as c 
    WINDOW w AS (PARTITION BY grandma_id ORDER BY RANDOM())) AS v1 
WHERE row_number <= 4; 

Das ist, was ich bisher getan habe:

s = Session() 

unique_users_contents = (s.query(Content).distinct(Content.grandma_id, 
                Content.author_id) 
         .subquery()) 

windowed_contents = (s.query(Content, 
          func.row_number() 
          .over(partition_by=Content.grandma_id, 
            order_by=func.random())) 
        .select_from(unique_users_contents)).subquery() 

contents = (s.query(Content).select_from(windowed_contents) 
      .filter(row_number >= 4)) ## how can I reference the row_number() value? 

result = contents 
for content in result: 
    print "%s\t%s\t%s" % (content.id, content.grandma_id, 
          content.author_id) 

Wie Sie sehen können, ist es ziemlich modelliert, aber ich habe keine Ahnung, wie man das row_number() Ergebnis der Unterabfrage von der äußeren Abfrage wo referenziert. Ich habe versucht, etwas wie windowed_contents.c.row_number und fügen Sie einen label() Aufruf auf der Fenster-Funktion, aber es funktioniert nicht, konnte kein ähnliches Beispiel in der offiziellen Dokumentation oder im Stackoverflow finden.

Wie kann dies erreicht werden? Und könnten Sie auch einen besseren Weg vorschlagen, diese Abfrage durchzuführen?

Antwort

13

windowed_contents.c.row_number gegen einen label() ist, wie Sie es tun würde, funktioniert für mich (man beachte die select_entity_from() Methode in SQLA 0.8.2 neu und wird hier in 0,9 vs. select_from() erforderlich):

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class Content(Base): 
    __tablename__ = 'contents' 

    grandma_id = Column(Integer, primary_key=True) 
    author_id = Column(Integer, primary_key=True) 


s = Session() 

unique_users_contents = s.query(Content).distinct(
          Content.grandma_id, Content.author_id).\ 
          subquery('c') 

q = s.query(
     Content, 
     func.row_number().over(
       partition_by=Content.grandma_id, 
       order_by=func.random()).label("row_number") 
    ).select_entity_from(unique_users_contents).subquery() 

q = s.query(Content).select_entity_from(q).filter(q.c.row_number <= 4) 

print q 
+0

' func.row_number(). over (... 'funktioniert nicht in 0.5 Version, so Workaround? – dumper

+5

0.5 wurde vor sechs Jahren veröffentlicht. Upgrade? Sonst eine Textform wie' text ("ROW NUMBER OVER") oder ähnlich ist wahrscheinlich Ihre direkteste Route. – zzzeek