Рекурсивный запрос из одной таблицы в SQL Server 2008 - PullRequest
13 голосов
/ 18 ноября 2009

У меня есть следующая таблица в базе данных SQL Server 2008:

Id  Name       ParentFolder
--  ----       ------------
1   Europe     NULL
2   Asia       NULL
3   Germany    1
4   UK         1
5   China      2
6   India      2
7   Scotland   4

ParentFolder - это идентификатор FK to Id в той же таблице. Я хотел бы создать представление, которое приводит к чему-то вроде этого:

Id  Name       FullName
--  ----       --------
1   Europe     Europe
2   Asia       Asia
3   Germany    Europe/Germany
4   UK         Europe/UK
5   China      Asia/China
6   India      Asia/India
7   Scotland   Europe/UK/Scotland

Как видите, мне нужно построить значения FullName путем рекурсивного использования отношения ParentFolder произвольное количество раз, пока не будет найден NULL.

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

Мне известна функция иерархии в SQL Server 2008, но, насколько мне известно, она работает только с фиксированным числом уровней рекурсии. В моем случае, однако, вы никогда не знаете, сколько уровней вы найдете, и они могут меняться от строки к строке.

Я также видел подобные вопросы, опубликованные здесь. Тем не менее, я думаю, что никто не спрашивал о построении «путей» для каждой строки в таблице. Извините, если я пропустил это.

Большое спасибо.

Ответы [ 4 ]

35 голосов
/ 18 ноября 2009

Попробуйте это:

    DECLARE @tbl TABLE (
         Id INT
        ,[Name] VARCHAR(20)
        ,ParentId INT
        )

    INSERT INTO @tbl( Id, Name, ParentId )
    VALUES
     (1, 'Europe', NULL)
    ,(2, 'Asia',   NULL)
    ,(3, 'Germany', 1)
    ,(4, 'UK',      1)
    ,(5, 'China',   2)
    ,(6, 'India',   2)
    ,(7, 'Scotland', 4)
    ,(8, 'Edinburgh', 7)
    ,(9, 'Leith', 8)

    ;
WITH  abcd
        AS (
              -- anchor
            SELECT  id, [Name], ParentID,
                    CAST(([Name]) AS VARCHAR(1000)) AS "Path"
            FROM    @tbl
            WHERE   ParentId IS NULL
            UNION ALL
              --recursive member
            SELECT  t.id, t.[Name], t.ParentID,
                    CAST((a.path + '/' + t.Name) AS VARCHAR(1000)) AS "Path"
            FROM    @tbl AS t
                    JOIN abcd AS a
                      ON t.ParentId = a.id
           )
SELECT * FROM abcd
2 голосов
/ 18 ноября 2009

Похоже, вы должны оформить заказ Поддержка CLR для Sql Sever.

Интеграция с CLR означает, что теперь вы можете писать хранимые процедуры, триггеры, пользовательские типы, пользовательские функции (скалярные и табличные) и пользовательские агрегатные функции, используя любой язык .NET Framework, включая Microsoft Visual Basic .NET и Microsoft Visual C #.

2 голосов
/ 18 ноября 2009

Я не уверен, будет ли это работать в вашем случае, но в этом примере http://www.pure -performance.com / 2009/03 / manage -ierarchical-data-in-sql / есть кое-что об использовании дополнительного столбца, называемого lineage.

Я успешно использовал этот метод.

1 голос
/ 30 января 2013

Я попробовал решение выше, но обнаружил, что это работает только для меня на 2 уровнях. (Возможно, я чего-то не понял или пропустил.)

Чтобы получить полный путь к решению m, я успешно выполнил следующую пользовательскую функцию:

CREATE FUNCTION GetFQN(@recid int)
RETURNS VARCHAR(1000)

AS

BEGIN
    DECLARE @path AS VARCHAR(1000)
    DECLARE @parent_recid AS INT

    SET @path           =   (SELECT BranchName FROM Branches WHERE Recid = @recid)
    SET @parent_recid   =   (SELECT recid_parent FROM Branches WHERE Recid = @recid)


    WHILE @parent_recid != -1
    BEGIN
        SET @path = (SELECT BranchName FROM Branches WHERE recid = @parent_recid) + '/' + @path 
        SET @parent_recid = (SELECT recid_parent FROM Branches WHERE recid = @parent_recid)
    END

    RETURN (@Path)
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...