SQLAlchemy 递归查询结果集排序

Posted

技术标签:

【中文标题】SQLAlchemy 递归查询结果集排序【英文标题】:SQLAlchemy recursive query result set ordering 【发布时间】:2021-12-24 07:27:07 【问题描述】:

我正在尝试使用 Python (3.9.6) 和 Flask-SqlAlchemy (2.5) 的递归查询来获取分层数据。这使用自引用数据,其中记录的 parent_id 指向同一表中的另一条记录。这是我的模型的简化版本:

class Post(db.Model):
    __tablename__ = "post"
    post_id = db.Column(db.String, primary_key=True)
    parent_id = db.Column(db.String, db.ForeignKey("post.post_id"), default=None)
    content = db.Column(db.String)
    children = db.relationship("Post", backref=db.backref("parent", remote_side=[post_id], lazy="joined"))

这是获取帖子及其所有子项的 SQLAlchemy 查询(它使用上下文管理器来确保在范围结束时提交或回滚数据库会话):

    # post_id = unique id of a post in the database
    with db_session_manager() as db_session:
        # build the list of filters here to use in the CTE
        filters = [
            Post.post_id == post_id,
            Post.parent_id == None
        ]
        # construct a self-referential, hierarchal query for the
        # post and it's comments
        posts_hierarchy = (
            db_session.query(Post, literal(0).label('level'))
                .filter(*filters)
                .cte(name='post_hierarchy', recursive=True)
        )
        parent = aliased(posts_hierarchy, name="p")
        children = aliased(Post, name="c")
        posts_hierarchy = (
            posts_hierarchy.union_all(
                db_session.query(Post, (parent.c.level + 1).label("level"))
                .filter(children.parent_id == parent.c.post_id)
                .filter(Post.post_id == children.post_id)
            )
        )         
        posts = (
            db_session.query(Post, posts_hierarchy.c.level)
            .select_entity_from(posts_hierarchy)
            .all()
        )

这在我取回根帖子及其所有子帖子时有效,但是,结果集包含以下内容:

root post
     1st root child
     2nd root child
     3rd root child
          1st child child (1)
          2nd child child (2)
          3rd child child (3)
          2nd child child (4)

我想要得到的是这样的:

root post
     1st root child 
          1st child child (1)
          2nd child child (2)
          3rd child child (3)
     2nd root child
          2nd child child (4)
     3rd root child

etc

我的 SQL 不够好,无法获得我想要的结果。我可以尝试什么来解决这个问题?

【问题讨论】:

嗨,道格。如果可以,请不要在您的帖子上签名 - 从历史上看,用户卡已被认为足以用于此目的。 【参考方案1】:

我已经弄清楚如何从递归 CTE 查询中获取我想要的内容。我这样修改了数据库表:

class Post(db.Model):
    __tablename__ = "post"
    post_id = db.Column(db.String, primary_key=True)
    parent_id = db.Column(db.String, db.ForeignKey("post.post_id"), default=None)
    sort_key = db.Column(db.String, nullable=False, default=SortKey())
    content = db.Column(db.String)
    children = db.relationship("Post", backref=db.backref("parent", remote_side=[post_id], lazy="joined"))

我添加了 sort_key 列,该列设置为自动递增函数,该函数返回值的字符串版本。我将递归 CTE SqlAlchemy 查询更新为:

        # build the list of filters here to use in the CTE
        filters = [
            Post.post_uid == post_uid,
            Post.parent_uid == None
        ]
        if current_user.is_anonymous or current_user.can_view_posts():
            filters.append(Post.active == True)

        # build the recursive CTE query
        hierarchy = (
            db_session
                .query(Post, Post.sort_key.label("sorting_key"))
                .filter(*filters)
                .cte(name='hierarchy', recursive=True)
        )
        children = aliased(Post, name="c")
        hierarchy = hierarchy.union_all(
            db_session
                .query(
                    children,
                    (hierarchy.c.sorting_key + " " + children.sort_key).label("sorting_key")
                )
                .filter(children.parent_uid == hierarchy.c.post_uid)
        )
        # query the hierarchy for the post and it's comments
        posts = (
            db_session
                .query(Post, hierarchy.c.sorting_key)
                .select_entity_from(hierarchy)
                .order_by(hierarchy.c.sorting_key)
                .all()
        )

合成的sorting_key 值是表中sort_key 的串联集,用于将结果正确排序为我正在寻找的分层格式。这基于两个资源 here 和 here。

希望其他人觉得这有帮助

【讨论】:

以上是关于SQLAlchemy 递归查询结果集排序的主要内容,如果未能解决你的问题,请参考以下文章

php无限级分类

关于SQL递归查询问题

SQL With (递归CTE查询)

SQL递归查询所有子节点

sql server使用cte递归查询获取树形的父节点/子节点

200分求助!SQL递归查询所有子节点