2014-10-16 3 views
4

Предположим, у меня есть таблица Author и стол Post, и у каждого автора может быть несколько сообщений.Используйте sqlalchemy, чтобы выбрать только одну строку из связанной таблицы.

Теперь, с одиночным sqlalchemy query, я хочу получить все мои активные Авторы и самую последнюю опубликованную Почту для каждого.

Я пытался пойти на это, получив список сообщений, которые joinedload Автора, используя подзапрос сгруппировать результаты вместе, как это:

subquery = DBSession.query(Author.id, func.max(Post.publish_date).label("publish_date")) \ 
    .join(Post.author) \ 
    .filter(Post.state == 'published') \ 
    .filter(Author.state == 'active') \ 
    .group_by(Author.id) \ 
    .subquery() 

query = DBSession.query(Post) \ 
    .options(joinedload(Post.author)) \ 
    .join(Post.author) \ 
    .join(subquery, and_(Author.id == subquery.c.id, 
         Post.publish_date == subquery.c.publish_date)) 

Но если у меня есть два сообщения от автор с тем же publish_date, и это самые новые сообщения, это означает, что я получаю этот автор дважды в списке результатов. И хотя я мог использовать второй подзапрос, чтобы устранить ошибки (возьмите func.max (Post.id)), кажется, действительно, действительно, неправильный путь для этого. Есть ли лучший способ сделать это?

(Опять же, я ищу одного запроса, так что я пытаюсь избежать запросов на столе Автор, а затем циклически и делать сообщения запроса для каждого автора в моих результатах.)

+0

Мне нравится [этот ответ] (http://stackoverflow.com/a/2043290/405075) делает то, что я хочу сделать, если я должен добавить предложение ORDER BY, но я не знаю, как перевести что от SQL в sqlalchemy. – shroud

+0

Если ваш db поддерживает функции окна с предложением over, вы можете использовать подход из [этого ответа] (http://stackoverflow.com/a/17457858/1587090) –

ответ

6

I бы сделать это следующим образом:

LastPost = aliased(Post, name='last') 
last_id = (
    session.query(LastPost.id) 
    .filter(LastPost.author_id == Author.id) 
    .order_by(LastPost.publish_date.desc()) 
    .order_by(LastPost.id.desc()) 
    .limit(1) 
    .correlate(Author) 
    .as_scalar() 
) 

query = (
    DBSession.query(Author, Post) 
    .outerjoin(Post, Post.id == last_id) 
) 

for author, last_post in query: 
    print(author, last_post) 

Как вы можете видеть, результат является tuple пар (Author, LastPost).
Изменить outerjoin на join, если вы хотите, чтобы авторы имели не менее Post.
Кроме того, я не задаю никаких отношений Author.post, чтобы избежать путаницы.

Смежные вопросы