【问题标题】:Use sqlalchemy to select only one row from related table使用 sqlalchemy 从相关表中只选择一行
【发布时间】:2014-12-11 08:40:16
【问题描述】:

假设我有一个 Author 表和一个 Post 表,每个 Author 可以有多个 Post。

现在,通过单个 sqlalchemy 查询,我想获取我所有的活跃作者以及每个作者最近发布的帖子。

我一直在尝试通过获取加入加载作者的帖子列表来解决此问题,使用子查询将结果分组在一起,如下所示:

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))

但是,如果我有两个来自作者的具有相同发布日期的帖子,并且那些是最新的帖子,这意味着我让该作者在我的结果列表中出现两次。虽然我可以使用第二个子查询来消除欺骗(使用 func.max(Post.id)),但这似乎是真的,真的是错误的方法。有没有更好的方法来解决这个问题?

(同样,我正在寻找单个查询,因此我试图避免在 Author 表上进行查询,然后循环并为我的结果中的每个 Author 执行 Post 查询。)

【问题讨论】:

  • 如果我要添加 ORDER BY 子句,我觉得 this answer 做了我想做的事情,但我不知道如何将它从 SQL 转换为 sqlalchemy。
  • 如果你的数据库支持带有over子句的窗口函数,你可以使用this answer中的方法

标签: python sqlalchemy


【解决方案1】:

我会这样做:

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)
如果您只希望作者至少拥有一个Post,请将outerjoin 更改为join
另外,我没有预加载任何关系 Author.post 以避免任何混淆。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 2021-08-20
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多