PostgreSQL LTREE递归查询:如何仅对指定行执行递归?
解决LTREE混合查询需求:指定节点本身+特定分支全后代
可以通过带条件的递归CTE实现,无需拆分查询再UNION,逻辑更紧凑且避免重复行:
方案一:标记递归需求(通用型)
适合需要区分多个节点是否递归的场景,通过标记列控制递归范围:
WITH RECURSIVE node_query AS ( -- 锚点:选中所有目标节点,标记是否需要展开后代 SELECT path, CASE WHEN path IN ('Top.Science'::ltree, 'Top.Collections'::ltree) THEN false WHEN path = 'Top.Collections.Pictures.Astronomy'::ltree THEN true END AS need_recurse FROM nodes WHERE path IN ( 'Top.Science'::ltree, 'Top.Collections'::ltree, 'Top.Collections.Pictures.Astronomy'::ltree ) UNION ALL -- 递归分支:仅处理标记为需要递归的节点,获取其所有后代 SELECT n.path, false AS need_recurse -- 后代无需再递归,防止循环或重复 FROM nodes n JOIN node_query p ON p.path <@ n.path -- 匹配父节点的所有后代 AND p.path != n.path -- 排除父节点本身(锚点已包含) WHERE p.need_recurse = true ) SELECT DISTINCT path FROM node_query;
方案二:直接限定递归触发条件(简化版)
如果只有一个分支需要递归,可以直接在递归连接条件里指定目标节点,省去标记列:
WITH RECURSIVE node_query AS ( -- 锚点:选中所有目标节点 SELECT path FROM nodes WHERE path IN ( 'Top.Science'::ltree, 'Top.Collections'::ltree, 'Top.Collections.Pictures.Astronomy'::ltree ) UNION ALL -- 仅递归Astronomy分支的后代 SELECT n.path FROM nodes n JOIN node_query p ON p.path = 'Top.Collections.Pictures.Astronomy'::ltree -- 仅针对该节点递归 AND p.path <@ n.path AND p.path != n.path ) SELECT DISTINCT path FROM node_query;
为什么这个方案能解决重复问题?
之前用<@关联全量递归时,Top.Collections会匹配到它的所有后代(包括Astronomy分支),而Astronomy自身的递归又会拉一次后代,导致重复。现在通过限制仅Astronomy节点触发递归,Top.Science和Top.Collections仅保留自身,不会展开子节点,从根源避免了重复。
内容的提问来源于stack exchange,提问作者sudoExclamationExclamation
相关产品推荐
相关产品推荐

