SQL嵌套集模型 - 如何找到每个分支的最深父节点(不是叶节点)

时间:2011-02-10 18:20:52

标签: nested-sets

鉴于这样的树:

A----B---------C----D
     |         |
     E----F    G
     |
     H

我需要找到C和E(每个独特分支的两个最深的节点; A-C和A-E)

我们的数据库使用嵌套集模型以及邻接列表作为备份,以便在左右值不同步的情况下维护树结构。

我可以排除所有叶子节点(rgt = lft + 1) 和根节点(lft = 1) 这让我看到了B E C.你可以想象这是一个非常简化的例子,我们的一些树有超过100个节点。如何在数据中消除这种噪音?

以上示例的数据如果存储在我们的数据库中。

 node | parent | lft | rgt |
------+--------+-----+-----+
   A  |  NULL  |    1|   16|
   B  |    A   |    2|   15|
   E  |    B   |    3|    8|
   F  |    E   |    4|    5|
   H  |    E   |    6|    7|
   C  |    B   |    9|   14|
   D  |    C   |   10|   11|
   G  |    C   |   12|   13|  

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

你是对的,第一步是通过它们的属性等于左+ 1来识别叶节点。下一步是找到那些叶节点的所有父节点:它们的左边小于叶的节点和右边大于叶子。最后一步是排除所有父项,但是具有最大左值的父项(即最接近叶节点)。

T-SQL中的一个例子,其中l是叶节点,p1是我们正在寻找的直接父节点,p2用于清除所有非直接父节点。

首先设置一个包含示例数据的测试表:

if object_id('tempdb..#nsm') is not null
    drop table #nsm;

select v.node, v.parent, v.lft, v.rgt
into #nsm
from (
    values 
       ('A'  ,     NULL,     1,   16),
       ('B'  ,    'A'   ,    2,   15),
       ('E'  ,    'B'   ,    3,    8),
       ('F'  ,    'E'   ,    4,    5),
       ('H'  ,    'E'   ,    6,    7),
       ('C'  ,    'B'   ,    9,   14),
       ('D'  ,    'C'   ,   10,   11),
       ('G'  ,    'C'   ,   12,   13)
   ) v (node, parent, lft, rgt)

这是检索您请求的节点C和E的查询:

select p1.node, p1.parent, p1.lft, p1.rgt
from #nsm p1
where exists (
            select *
            from #nsm l
            where l.rgt = l.lft + 1
                and p1.lft < l.lft
                and p1.rgt > l.rgt
                and not exists (
                        select *
                        from #nsm p2
                        where p2.lft < l.lft
                            and p2.rgt > l.rgt
                            and p2.lft > p1.lft
                    )
        )