2012-09-07 7 views
5

Estoy intentando que mi subconsulta de popular_query elimine a duca Place.id, pero no la elimina. Este es el código a continuación. Intenté usar distinct pero no respeta la regla order_by.¿Cómo puedo consultar filas con valores únicos en una columna unida?

SimilarPost = aliased(Post) 
SimilarPostOption = aliased(PostOption) 
popular_query = (db.session.query(Post, func.count(SimilarPost.id)). 
     join(Place, Place.id == Post.place_id). 
     join(PostOption, PostOption.post_id == Post.id). 
     outerjoin(SimilarPostOption, PostOption.val == SimilarPostOption.val). 
     join(SimilarPost,SimilarPost.id == SimilarPostOption.post_id). 
     filter(Place.id == Post.place_id). 
     filter(self.radius_cond()). 
     group_by(Post.id). 
     group_by(Place.id). 
     order_by(desc(func.count(SimilarPost.id))). 
     order_by(desc(Post.timestamp)) 
     ).subquery().select() 

all_posts = db.session.query(Post).select_from(filter.pick()).all() 

hice una impresión de prueba con

print [x.place.name for x in all_posts] 

[u'placeB', u'placeB', u'placeB', u'placeC', u'placeC', u'placeA'] 

¿Cómo puedo solucionar este problema?

Gracias!

+0

¿Respeta el orden si elimina la cláusula 'group_by (Place.id)' y agrega 'distinct (Place.id)' en su lugar? Creo que el 'group_by' no sería necesario si usas' distinct'. – Nicholas

+0

¿'' self.radius_cond() 'y' filter.pick() 'cosas que ha definido en otro lugar? No veo nada que realmente haga uso de 'popular_query'. –

Respuesta

4

Esto debe conseguir lo que quiere:

SimilarPost = aliased(Post) 
SimilarPostOption = aliased(PostOption) 
post_popularity = (db.session.query(func.count(SimilarPost.id)) 
     .select_from(PostOption) 
     .filter(PostOption.post_id == Post.id) 
     .correlate(Post) 
     .outerjoin(SimilarPostOption, PostOption.val == SimilarPostOption.val) 
     .join(SimilarPost, sql.and_(
       SimilarPost.id == SimilarPostOption.post_id, 
       SimilarPost.place_id == Post.place_id) 
     ) 
     .as_scalar()) 
popular_post_id = (db.session.query(Post.id) 
     .filter(Post.place_id == Place.id) 
     .correlate(Place) 
     .order_by(post_popularity.desc()) 
     .limit(1) 
     .as_scalar()) 

deduped_posts = (db.session.query(Post, post_popularity) 
     .join(Place) 
     .filter(Post.id == popular_post_id) 
     .order_by(post_popularity.desc(), Post.timestamp.desc()) 
     .all()) 

no puede hablar con el rendimiento de ejecución con grandes conjuntos de datos, y puede haber una solución mejor, pero eso es lo que logró sintetizar desde bastantes fuentes (MySQL JOIN with LIMIT 1 on joined table, SQLAlchemy - subquery in a WHERE clause, SQLAlchemy Query documentation). El mayor factor de complicación es que aparentemente necesita usar as_scalar para anidar las subconsultas en los lugares correctos y, por lo tanto, no puede devolver tanto la Id. De la publicación como la cuenta de la misma subconsulta.

FWIW, esto es un poco gigante y estoy de acuerdo con el usuario1675804 en que el código SQLAlchemy es tan profundo que no se puede mantener. Debería echar un vistazo a otras soluciones de baja tecnología disponibles, como agregar columnas a la base de datos o hacer más trabajo en código python.

1

No quiero sonar como el tipo malo aquí, pero ... en mi opinión, su enfoque del problema parece mucho menos que óptimo ... si está utilizando postgresql podría simplificarlo todo utilizando ... pero un mejor enfoque teniendo en cuenta mi suposición de que estas publicaciones se leerán con mucha más frecuencia que la actual sería agregar algunas columnas a sus tablas que se actualicen mediante desencadenantes en insertar/actualizar a otras tablas, al menos si el rendimiento es probable volver a ser un problema esta es la solución que me gustaría con

No estoy muy familiarizado con sqlalchemy, por lo que no puedo escribirlo en código claro, pero la única otra solución que puedo usar utiliza al menos un subconsulta para seleccionar las cosas de order by para cada una de las columnas en group by, y eso agregará significativamente a su consulta ya lenta

Cuestiones relacionadas