Нахождение глубины многопользовательской иерархии - SQL - PullRequest
2 голосов
/ 31 октября 2011

У меня есть таблица с двумя столбцами: мама - узел Эта таблица составляет основу иерархии. Мать относится к узлу. У каждого узла может быть несколько матерей, и у каждой матери может быть несколько детей. Это достигается несколькими рядами. Если mother = NULL, то узел является узлом верхнего уровня. Может быть несколько узлов верхнего уровня, и узел может быть как узлом верхнего уровня, так и дочерним узлом другого узла. например:

INSERT INTO MYTABLE VALUES(NULL, 2)
INSERT INTO MYTABLE VALUES(1, 2)

Сейчас я строю процедуру, которая должна знать максимальную глубину иерархии. Допустим, узел E является дочерним узлом D, который является дочерним узлом C. Узел C является узлом верхнего уровня, а также дочерним узлом B, который является дочерним узлом A Узел А является только узлом верхнего уровня. Если мы говорим, что узел A имеет глубину = 0. Тогда в этом случае глубина узла E должна быть 4.

Кто-нибудь знает, как я могу построить утверждение, которое найдет для меня эту глубину? Он должен найти максимальную глубину каждого узла в таблице и затем вернуть максимальное значение из них.

Спасибо!

Использование SQL Server 2008, кстати.

EDIT:

Интерес представляет ТОЛЬКО абсолютная максимальная глубина таблицы. Не глубина отдельных узлов.

Ответы [ 2 ]

8 голосов
/ 31 октября 2011

Попробуйте это, он найдет все нижние уровни иерархии

declare @mytable table(id int, parent_id int)

INSERT INTO @MYTABLE VALUES(1, NULL) 
INSERT INTO @MYTABLE VALUES(2, 1) 
INSERT INTO @MYTABLE VALUES(3, 1) --*
INSERT INTO @MYTABLE VALUES(4, 2) 
INSERT INTO @MYTABLE VALUES(5, 4) --*

;with a as
(
    select 
       id, 
       parent_id, 
       1 lvl 
    from @mytable 
    where parent_id is null
    union all
    select 
        b.id, 
        b.parent_id, 
        lvl+1 
    from @mytable b 
        join a on a.id = b.parent_id
)
select 
    a.id, 
    a.parent_id, 
    a.lvl 
from a
    left join a b on a.id = b.parent_id
where b.id is null
option (maxrecursion 0)
0 голосов
/ 31 октября 2011

Хорошо. Я нашел решение.

Сначала я создал временную таблицу с двумя дополнительными столбцами:

    CREATE TABLE #ParentChildTempTable
(
    Node NVARCHAR(50),
    Parent NVARCHAR(50),
    Depth TINYINT,
    Measure_Depth BIT
)

Затем я устанавливаю глубину истинных узлов верхнего уровня на 0. Ложным узлам верхнего уровня будет присвоено значение Measure_Depth, равное 0.

    UPDATE #ParentChildTempTable SET Depth = 0 WHERE Parent IS NULL AND node not in 
(select Node from #ParentChildTempTable temp2 where temp2.Parent is not null)

UPDATE #ParentChildTempTable SET Measure_Depth = 0 WHERE Parent IS NULL AND node in 
(select Node from #ParentChildTempTable temp2 where temp2.Parent is not null)

Затем я возвращаюсь с верхнего уровня до тех пор, пока каждый узел не будет иметь глубину (ожидаем ложно-верхний уровень)

    WHILE EXISTS (SELECT * FROM #ParentChildTempTable WHERE Depth IS NULL AND Measure_Depth IS NULL) 
    UPDATE T SET T.Depth = P.Depth + 1
    FROM #ParentChildTempTable AS T 
    INNER JOIN #ParentChildTempTable AS P ON (T.Parent=P.Node) 
    WHERE P.Depth>=0 
    AND T.Depth IS NULL

И вуаля! Максимальная глубина найдена:

DECLARE @MaxDepth INT = (SELECT MAX(Depth) FROM #ParentChildTempTable)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...