我在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。我想创建一个结果如下的视图:
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
正如您所看到的,我需要通过递归使用ParentFolder关系构建FullName值,直到找到NULL为止。
编辑。表中的每一行“都知道”其他行是否为其父级,但不知道其在层次结构中的绝对位置。出于这个原因,每个行在层次结构树中存储其绝对位置的沿袭系统是不合适的。
我知道SQL Server 2008的hierarchyid功能,但据我所知,它只适用于固定数量的递归级别。但是,在我的情况下,你永远不知道你会找到多少级别,并且它们可能会在行之间发生变化。
我也在这里发过类似的问题。但是,我认为没有人问过为表格中的每一行构建“路径”。对不起,如果我错过了。
非常感谢。
答案 0 :(得分:35)
试试这个:
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
答案 1 :(得分:2)
我不确定这是否适用于您的情况,但在此示例http://www.pure-performance.com/2009/03/managing-hierarchical-data-in-sql/中,有一些关于使用名为lineage的额外列的信息。
我已成功使用此方法。
答案 2 :(得分:2)
听起来你应该为Sql Sever结帐CLR support。
CLR集成意味着您现在可以使用任何.NET Framework语言编写存储过程,触发器,用户定义类型,用户定义函数(标量和表值)以及用户定义的聚合函数,包括Microsoft Visual Basic .NET和Microsoft Visual C#。
答案 3 :(得分:1)
我尝试了上面的解决方案,但发现这只适用于我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