Рекурсивный запрос с одинаковой таблицей в SQL Server 2008
У меня есть следующая таблица в базе данных 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 для идентификатора в той же таблице. Я хотел бы создать представление, которое приведет к чему-то вроде этого:
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, но, насколько я знаю, она работает только с фиксированным количеством уровней рекурсии. В моем случае, однако, вы никогда не знаете, сколько уровней вы найдете, и они могут меняться от строки к строке.
Я также видел похожие вопросы, которые вы писали здесь. Однако я думаю, что никто не спрашивал о построении "путей" для каждой строки в таблице. Извините, если я пропустил это.
Большое спасибо.
Ответы
Ответ 1
Попробуйте следующее:
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
Я не уверен, что это будет работать в вашем случае, но в этом примере http://www.pure-performance.com/2009/03/managing-hierarchical-data-in-sql/ есть что-то об использовании дополнительного столбец, называемый lineage.
Я успешно использовал этот метод.
Ответ 3
Похоже, вы должны проверить поддержка CLR для Sql Sever.
Интеграция CLR означает, что теперь вы можете писать хранимые процедуры, триггеры, пользовательские типы, определяемые пользователем функции (скалярные и табличные) и определяемые пользователем агрегированные функции с использованием любого языка .NET Framework, включая Microsoft Visual Basic.NET и Microsoft Visual С#.
Ответ 4
Я попробовал решение выше, но обнаружил, что это работает только для меня до 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