SQL Server CTE выбирает одну ветвь древовидной структуры до корня - PullRequest
5 голосов
/ 22 декабря 2011

Можно ли передать параметр в CTE, который выбирает узел, а затем выбирает его родителя до корня, где parentId равен нулю?

В моем коде ниже, если я передам параметр, который выбирает Rain Coats, а затем рекурсивно поднимает дерево до мужской одежды, где его parentId равно нулю, и выбирает все узлы в этой ветви, включая дочерние.Может ли кто-нибудь помочь мне с этим, пожалуйста.Мой пример просто повторяется и показывает глубину

Пример SQL:

DECLARE @Department TABLE
(
    Id INT NOT NULL,
    Name varchar(50) NOT NULL,
    ParentId int NULL
)

INSERT INTO @Department SELECT 1, 'Toys', null
INSERT INTO @Department SELECT 2, 'Computers', null
INSERT INTO @Department SELECT 3, 'Consoles', 2
INSERT INTO @Department SELECT 4, 'PlayStation 3', 3
INSERT INTO @Department SELECT 5, 'Xbox 360', 2
INSERT INTO @Department SELECT 6, 'Games', 1
INSERT INTO @Department SELECT 7, 'Puzzles', 6
INSERT INTO @Department SELECT 8, 'Mens Wear', null
INSERT INTO @Department SELECT 9, 'Mens Clothing', 8
INSERT INTO @Department SELECT 10, 'Jackets', 9
INSERT INTO @Department SELECT 11, 'Rain Coats', 10

;WITH c 
AS
(
    SELECT Id, Name,1 AS Depth
    FROM @Department
    WHERE ParentId is null  

         UNION ALL

         SELECT t.Id, t.Name, c.Depth + 1 AS 'Level'
    FROM @Department T  
    JOIN c ON t.ParentId = c.Id

)
SELECT * FROM c WHERE c.Id = 3

Ответы [ 2 ]

13 голосов
/ 22 декабря 2011

Ваш текущий CTE просто показывает все элементы в дереве с их Depth и всеми другими свойствами.Таким образом, он работает нормально.

Чтобы сделать то, что вы ищете, вы должны почти «инвертировать» CTE - сначала захватите интересующий вас элемент как «якорь» вашего CTE.и затем "recercise" до корня:

DECLARE @StartID INT = 11

;WITH c 
AS
(
    SELECT Id, ParentId, Name, 1 AS Depth
    FROM @Department
    WHERE Id = @startID

    UNION ALL

    SELECT t.Id, t.ParentId, t.Name, c.Depth + 1 AS 'Level'
    FROM @Department T  
    INNER JOIN c ON t.Id = c.ParentId
)
SELECT * 
FROM c 

Это сделает то, что вы ищете, и выведите:

Id ParentId  Name            Depth
11    10     Rain Coats        1
10     9     Jackets           2
 9     8     Mens Clothing     3
 8   NULL    Mens Wear         4

Обновление

Для обратного порядка глубины вы можете использовать это:

;WITH c 
AS
(
    SELECT Id, ParentId, Name, 1 AS Depth
    FROM @Department
    WHERE Id = @startID

    UNION ALL

    SELECT t.Id, t.ParentId, t.Name, c.Depth + 1 AS 'Level'
    FROM @Department T  
    INNER JOIN c ON t.Id = c.ParentId
)
SELECT Id,
       ParentID, 
       Name,
       MAX(Depth) OVER() - Depth + 1 AS InverseDepth
FROM c

Вывод из этого:

Id ParentId  Name            InverseDepth
11    10     Rain Coats        4
10     9     Jackets           3
 9     8     Mens Clothing     2
 8   NULL    Mens Wear         1
4 голосов
/ 22 декабря 2011

В настоящее время ваш CTE имеет корень в качестве своего якоря и переходит от родителя к потомку в своей рекурсивной части. Если вам нужно целое дерево, вам нужно начать с интересующего ребенка и продолжить свой путь. Это один из способов сделать это. Я ввел новый столбец StartingId, который остается постоянным, пока мы идем вверх по дереву - это то, что мы выберем на основе:

;WITH c 
AS
(
    SELECT Id AS StartingId, Id, ParentId, Name, 0 AS Height
    FROM @Department

    UNION ALL

    SELECT c.StartingId, p.Id, p.ParentId, p.Name, c.Height + 1 AS Height
    FROM @Department p INNER JOIN c ON p.Id = c.ParentId
)
SELECT * FROM c WHERE c.StartingId = 11

дает

StartingId  Id          ParentId    Name                                   Height
----------- ----------- ----------- ----------------------------------------------
11          11          10          Rain Coats                             0
11          10          9           Jackets                                1
11          9           8           Mens Clothing                          2
11          8           NULL        Mens Wear                              3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...