SQL Server中多对多层次结构的数据结构

时间:2014-04-22 15:06:21

标签: sql sql-server data-structures

我的系统中已经有以下数据结构。

ItemDetails

ID Name
--------
1  XXX
2  YYY
3  ZZZ
4  TTT
5  UUU
6  WWW

层次结构位于单独的表中(具有多对多的关系)

ItemHierarchy

ParentCode ChildCode
--------------------
1            2
1            3
3            4
4            5
5            3
5            6

正如您所看到的那样3是1和3的子节点。我想遍历记录,例如来自节点3的记录。

我需要编写一个存储过程并获取3的所有祖先和3的所有子节点。

您能告诉我是否有可能提取数据?如果是这样,那么哪种数据结构就可以了。

请注意,我的表包含100万条记录,其中40%有多个层次结构。

我做过' CTE'使用级别并根据层次结构递增它,但是当我们从根节点遍历到叶级节点时,我得到最大递归错误。我试过了HierarchyID'但是当节点有多个父节点时无法获得所有细节。

更新:我可以将递归限制设置为max并运行查询。由于它有数百万行,我根本无法获得输出。

我想创建一个数据结构,使其能够从上到下或从下到上(在任何节点级别)提供信息。

有人可以帮助我吗?

1 个答案:

答案 0 :(得分:2)

建议不要使用RDBMS进行分层数据结构,而是建立graph database的原因。
BTW遵循 Closure Table 模式会对您有所帮助 Closure Table解决方案是一种存储层次结构的简单而优雅的方法。它涉及存储树中的所有路径,而不仅仅是那些具有直接父子关系的路径。

使用该模式的关键是如何填写ItemHierarchy表格 在树中为树中的每对节点存储一行共享祖先/后代关系,即使它们在树中由多个级别分隔。还要为每个节点添加一行以引用自身 认为我们有一个简单的图表如下: enter image description here
带箭头的箭头显示ItemHierarchy表中的行: enter image description here
要检索#3的后代:

SELECT c.*
FROM ItemDetails AS ID
JOIN ItemHierarchy AS IH ON ID.ID = IH.ChildCode
WHERE IH.ParentCode = 3;

检索#3的祖先:

SELECT c.*
FROM ItemDetails AS ID
JOIN ItemHierarchy AS IH ON ID.ID = IH.ParentCode 
WHERE IH.ChildCode = 3;

首先插入一个新的叶节点,例如#5的新子节点 插入自引用行。然后添加一组行的副本 将注释#5作为后代引用的TreePath(包括行) 其中#5引用自身),用后代替换后代 新项目的编号: INSERT INTO ItemHierarchy(parentCode,childCode)

SELECT IH.parentCode, 8
FROM ItemHierarchy AS IH
WHERE IH.childCode = 5
UNION ALL
SELECT 8, 8;

要删除完整的子树,例如#4及其后代,请删除ItemHierarchy中引用#4的所有行作为 后代,以及引用#4中任何一个的所有行 后代作为后代:

DELETE FROM ItemHierarchy 
WHERE chidCode IN (SELECT childCode
FROM ItemHierarchy 
WHERE parrentCode = 4);



更新
由于您向我们展示的样本数据会导致递归循环(不是层次结构),如:

1 -> 3 -> 4 -> 5 -> 3 -> 4 -> 5

以下路径枚举模式将对您有所帮助 像/usr/local/lib/这样的UNIX路径是文件系统的路径枚举, 其中usrlocal的父级,turn中的父级是lib的父级。
您可以从ItemHierarchy表创建一个表或视图,并将其命名为EnumPath
EnumPath(NodeCode, Path)

对于样本数据,我们将有:
enter image description here
要找到节点#4的祖先:

select distinct E1.NodeCode from EnumPath E1
inner join EnumPath E2
On E2.path like E1.path || '%'
where E2.NodeCode = 4 and E1.NodeCode != 4;

要查找节点#4的后代:

select distinct E1.NodeCode from EnumPath E1
inner join EnumPath E2
On E1.path like E2.path || '%'
where E2.NodeCode = 4 and E1.NodeCode != 4;

Sqlfiddle demo