You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLAlchemy自引用层级结构如何获取根节点与叶子节点/根叶配对

自引用层级结构相关查询实现方案

1. 查询所有叶子节点

叶子节点定义:没有任何子节点的节点,即不存在其他行的parent_id等于当前行的id
直接用NOT EXISTS语法即可实现单句查询,代码如下:

from sqlalchemy import exists
from sqlalchemy.orm import aliased

s = session()
ChildModel = aliased(Model)
# 查询所有叶子节点
leaf_nodes = s.query(Model).filter(
    ~exists().where(ChildModel.parent_id == Model.id)
).all()

2. 批量查询所有根节点的全量后代

不需要循环遍历每个根节点单独查询,直接修改递归CTE的起始条件为所有根节点即可,还可以在CTE中新增root_id字段标记每个节点所属的根节点,方便后续统计:

s = session()
# 递归CTE,起始为所有根节点,携带root_id字段
recursive_cte = s.query(
    Model.id,
    Model.parent_id,
    Model.id.label("root_id")  # 根节点的root_id就是自身id
).filter(Model.parent_id.is_(None)).cte(name="recursive_cte", recursive=True)

# 递归关联子节点,继承父节点的root_id
recursive_cte = recursive_cte.union_all(
    s.query(
        Model.id,
        Model.parent_id,
        recursive_cte.c.root_id
    ).filter(Model.parent_id == recursive_cte.c.id)
)

# 一次查询得到所有节点及对应所属根节点id
all_node_with_root = s.query(recursive_cte).all()

3. 查询所有根-叶配对数据

在上面递归CTE的基础上,过滤出叶子节点即可得到所有根和对应叶子的配对关系:

from sqlalchemy import exists
from sqlalchemy.orm import aliased

s = session()
ChildModel = aliased(Model)

# 先定义带root_id的递归CTE,和上面逻辑一致
recursive_cte = s.query(
    Model.id.label("node_id"),
    Model.parent_id,
    Model.id.label("root_id")
).filter(Model.parent_id.is_(None)).cte(name="recursive_cte", recursive=True)

recursive_cte = recursive_cte.union_all(
    s.query(
        Model.id.label("node_id"),
        Model.parent_id,
        recursive_cte.c.root_id
    ).filter(Model.parent_id == recursive_cte.c.id)
)

# 过滤出是叶子节点的行,得到根-叶配对
root_leaf_pairs = s.query(
    recursive_cte.c.root_id,
    recursive_cte.c.node_id.label("leaf_id")
).filter(
    ~exists().where(ChildModel.parent_id == recursive_cte.c.node_id)
).all()

如果需要同时拿到根节点和叶子节点的完整Model对象,只需修改查询字段关联对应表即可。

内容的提问来源于stack exchange,提问作者Oskar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 17:36:04