Как я могу произвести путь иерархии в SQL, который приводит к данному узлу?

В моей базе данных MS SQL 2008 R2 у меня есть этот стол:

TABLE [Hierarchy]
[ParentCategoryId] [uniqueidentifier] NULL,
[ChildCategoryId] [uniqueidentifier] NOT NULL

Я должен написать вопрос, который произведет все пути, которые приводят к данному Узлу.

Позволяет говорит это, у меня есть следующее дерево:

A
-B
--C
-D
--C

Который был бы сохранен как:

NULL | A
A    | B
A    | D
B    | C
D    | C

Прося Пути для C, я хотел бы возвратить два пути (написанный более или менее как это):

A > B > C,
A > D > C
4
nl ja de
Проверьте рекурсивные общие выражения стола или просто рекурсивные запросы. Есть тонны примера здесь на ТАК
добавлено автор a_horse_with_no_name, источник
Ах, забыл упоминать версию, I' ll добавляют это к вопросу, но it' s MS SQL 2008 R2
добавлено автор Dugan, источник
Боковая панель; Попробованный, чтобы предположить, почему вы хотели бы знать каждый маршрут, доступный между узлами. Предполагаемый, возможно, это было так, чтобы вы могли вычислить кратчайший путь. Если это так: Dijkstra' s алгоритм
добавлено автор MarkD, источник
Какую версию SQL Server вы используете? Ключевое слово, чтобы искать это you' поиск ре является Иерархическими Вопросами. I' m не слишком знакомый с SQLServer, но это было бы тривиальной задачей в Oracle, используя , соединяются , и начинаются с операторы, и насколько я знаю, что у более новых версий SQLServer уже есть большинство особенностей, которые имеет Oracle
добавлено автор beder, источник

3 ответы

Here is my solution, Sql Fiddle

DECLARE @child VARCHAR(10) = 'C'

    ;WITH children AS
    (

       SELECT 
         ParentCategoryId,
        CAST(ISNULL(ParentCategoryId + '->' ,'')  + ChildCategoryId AS VARCHAR(4000)) AS Path
       FROM Hierarchy
       WHERE ChildCategoryId =  @child
     UNION ALL
       SELECT 
         t.ParentCategoryId,
         list= CAST(ISNULL(t.ParentCategoryId  + '->' ,'')  + d.Path AS VARCHAR(4000))
       FROM Hierarchy t
       INNER JOIN children  AS d
            ON t.ChildCategoryId = d.ParentCategoryId
     )

    SELECT Path 
    from children c
    WHERE ParentCategoryId IS NULL

Продукция:

A->D->C 
A->B->C 

UPDATE:

@AlexeiMalashkevich, чтобы просто получить id, можно попробовать это

Скрипка SQL

DECLARE @child VARCHAR(10) = 'C'

;WITH children AS
(

   SELECT 
     ParentCategoryId,
     ChildCategoryId  AS Path
   FROM Hierarchy
   WHERE ChildCategoryId =  @child
 UNION ALL
   SELECT 
     t.ParentCategoryId,
     d.ParentCategoryId 
   FROM Hierarchy t
   INNER JOIN children  AS d
        ON t.ChildCategoryId = d.ParentCategoryId
 )

SELECT DISTINCT PATH
from children c
7
добавлено
Вы получаете проверку на то, чтобы также представить меня SqlFiddle
добавлено автор Dugan, источник
@AlexeiMalashkevich, вы могли, пожалуйста, дать пример своей желаемой продукции?
добавлено автор EricZ, источник
@AlexeiMalashkevich, Ответ обновляется.
добавлено автор EricZ, источник
У мая @EricZ быть вами есть решение получить только путь id' s вместо пути? Конечно, я могу разобрать его, но могу быть есть более красивое решение?
добавлено автор Alexei Malashkevich, источник
Уверенный @EricZ. Для предыдущего примера это должны быть 4 ряда ' A' ' D' ' B' ' C'.
добавлено автор Alexei Malashkevich, источник
@EricZ BN\rilliant!Thank you very much!
добавлено автор Alexei Malashkevich, источник

Возможное решение состоит в том, чтобы использовать рекурсивный CTE, как упомянуто @a_horse_with_no_name:

CREATE TABLE [Hierarchy](
[ParentCategoryId] CHAR(1) NULL,
[ChildCategoryId] CHAR(1) NOT NULL
);


INSERT INTO Hierarchy
SELECT NULL, 'A' UNION ALL
SELECT 'A', 'B' UNION ALL
SELECT 'A', 'D' UNION ALL
SELECT 'B', 'C' UNION ALL
SELECT 'D', 'C';


WITH CTE AS (
    SELECT 
        ParentCategoryId, ChildCategoryId, 
        CAST(ISNULL(ParentCategoryId,'') + ChildCategoryId AS VARCHAR(255)) [Path] 
    FROM Hierarchy
    WHERE ParentCategoryId IS NULL

    UNION ALL

    SELECT 
        H.ParentCategoryId, H.ChildCategoryId, 
        CAST(C.[Path] + ' > ' + H.ChildCategoryId AS VARCHAR(255)) [Path] 
    FROM Hierarchy H
    INNER JOIN CTE C ON C.ChildCategoryId = H.ParentCategoryId
) SELECT * FROM CTE;
2
добавлено
Необходимо начать помещать точки с запятой в конец заявлений: sqlblog.com/blogs/aaron_bertrand/archive/2009/09/03/…
добавлено автор a_horse_with_no_name, источник
Это исключило бы высокоуровневых родителей без любых детей и потребует, чтобы немного манипуляции составляло использование uniqueidentifiers как табличные типы данных, но общая логика совпадает с моим ответом. Вы побеждаете меня к ответу на три минуты, престижность.:)
добавлено автор Eric J. Price, источник
Спасибо @a_horse_with_no_name, положительная сторона и связь, я соглашаюсь.
добавлено автор Oleksandr Kucher, источник
@Love2Learn - да, вы правы, это не идеальное решение, но так же, как пример автору. 3 минуты похожи на вечность - ваш SQL Server выполнил миллиард операций в это время:)
добавлено автор Oleksandr Kucher, источник

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

Create  Function dbo.IdentifyHierarchyPaths (@DeepestChildNode UniqueIdentifier)
Returns @hierarchy Table
(
        Hierarchy Varchar(Max)
)
As
Begin
        ;With   BuildHier As
        (
                Select  Convert(Varchar(Max),h2.ChildCategoryId) As child, Convert(Varchar(Max),h1.ChildCategoryId) + ' > ' +  Convert(Varchar(Max),h2.ChildCategoryId) As hier
                From    Hierarchy h1
                Left    Join Hierarchy h2
                        On  h1.ChildCategoryId = h2.ParentCategoryId
                Where   h1.ParentCategoryId Is Null
                Union   All
                Select  Convert(Varchar(Max),h1.ChildCategoryId) As child, bh.hier + ' > ' +  Convert(Varchar(Max),h1.ChildCategoryId) As hier
                From    BuildHier bh
                Join    Hierarchy h1
                        On  bh.child = h1.ParentCategoryId
        ),      HierWithTopLevel As
        (
                Select  Convert(Varchar(Max),ChildCategoryId) As hierarchy
                From    Hierarchy
                Where   ParentCategoryId Is Null
                Union   
                Select  hier
                From    BuildHier
        )
        Insert  @hierarchy
        Select  hierarchy
        From    HierWithTopLevel
        Where   Right(hierarchy,36) = Convert(Varchar(36),@DeepestChildNode);
        Return;
End;
0
добавлено
SqlCom.ru - Стиль жизни SQL
SqlCom.ru - Стиль жизни SQL
908 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только MS SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz). Предложения в @sql_ninja

SQL_Ninja
SQL_Ninja
340 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz)