2011-03-08 66 views
0

这个问题类似: How do I query for all the nodes between two nodes in a tree?返回所有节点在许多一对多层次树

但我有一个闭合(扁平化)表,一个孩子可以有很多家长和ID遍历不一定按顺序。嵌套深度没有限制。

假设循环引用是不可能的... 我想返回遍历层次结构所需的所有行。

ParentID ID RowNumber(Reference) 
1   2  1 
2   4  2 
4   3  3 
3   5  4 
1   6  5 
6   7  6 
2   8  7 
3   9  8 
1   8  9 
6   8  10 

鉴于1我将如何编写一个查询返回的所有行(得到所有后代relationsips):

下表假设?

同样地,给定的2我期望行2,3,4,7,8

鉴于6我期望的行6和10

偶尔假阳性是可接受的,因为在被复制的行结果。缺失的行是不可接受的

实现在MSACCESS和SQL Server 2000+

+0

只是为了澄清,你的意思是一个孩子可以有很多*父母*而不是许多*祖先*,对吗?我只问,因为你发布的样本数据没有显示任何有多个父母的孩子,但是4,3,5,7有多个祖先。 – mwolfe02 2011-03-08 19:43:50

+0

一个孩子可以有许多父母*和*许多后代。我将添加更多示例 – Matthew 2011-03-08 19:46:18

+0

此外,您希望基于示例数据实现的示例查询结果将非常有用。一定要使用捕捉所有可能的复杂性的样本数据(即,具有多个父母的孩子等)。 – mwolfe02 2011-03-08 19:48:03

回答

1

由于你需要在没有的地方建模数据des可以有多个父母,嵌套集合/ MPTT解决方案将不起作用。另一种选择是使用closure table

您需要创建举行对项目的每一个祖先的后代(反之亦然)的附加表:

 
AncID DesID 
    1  2 
    1  6 
    1  4 
    1  8 
    1  7 
    1  3 
    1  5 
    1  9 
    2  4 
    2  8 
    2  3 
    2  5 
    2  9 
    4  3 
    4  5 
    4  9 
    3  5 
    3  9 
    6  7 

那么你可以使用一个连接来得到你所需要的物品:

SELECT * 
FROM Tbl INNER JOIN Closure ON Tbl.ID=Closure.DesID 
WHERE Closure.AncID = 2 
+0

我对这种方法很熟悉(它被应用于问题中我在OP中链接),这将需要额外的数据写入处理,这是不可取的,我开始相信它是唯一可行的方法来获得单个查询的结果,请注意,在我的问题中,它是一张“扁平”的桌子而不是您使用的公认名称。 – Matthew 2011-03-08 22:34:46

+0

除非您使用具有对相邻列表模型(Oracle,SQL Server 2005+)的专有支持的数据库引擎,否则您需要在写入时或读取时进行额外的处理。如果您想避免管理其他信息,则可以在读取时循环访问记录集。这将比使用查询慢,但它将需要较少的维护。这是一个折衷。这取决于你的具体要求。 – mwolfe02 2011-03-09 12:21:31

+0

尽管我不会实现传递闭包表,但我将其标记为答案,因为它是一个可行的解决方案(不是我打算使用的解决方案) – Matthew 2011-03-31 19:50:00

0

检查此线程,看看它回答使用ANSI SQL你的问题。基本上Oracle有一个很好的方法来使用CONNECT BY子句来做到这一点,你需要使用ANSI SQL来复制它。 Simulation of CONNECT BY PRIOR of ORACLE in SQL SERVER

+0

CTE在SQL Server 2005中不可用 – RichardTheKiwi 2011-03-08 19:54:37

+1

@Richard Typo我想。不适用于SQL Server 2000. – 2011-03-08 20:05:12

+0

我的思维短路..它应该读取CTE在* SQL Server 2000中不可用,解决方案链接用于* SQL Server 2005.谢谢迈克尔 – RichardTheKiwi 2011-03-08 20:06:31

3

对于SQL Server:Adjacency list vs. nested sets: SQL Server

喷气/ MS Access中,递归查询是不是一种选择,所以nested sets将要走的路。对于一个样本:http://www.mvps.org/access/queries/qry0023.htm

对嵌套组的一些背景:

要实现你需要在你的表中添加和维护两个附加列一组嵌套的解决方案:LtRt(左,右,分别)。您可以通过执行修改的预定义树遍历来为这些列分配值来填充这些列。这可以通过递归功能轻松完成。然后,您可以在SELECT时间使用左值和右值来确定后代。

无论何时只要数据发生变化,折衷就需要更多的处理,但在检索数据时要快得多。

这个概念有点不直观,肯定有学习曲线,但我个人使用它的效果很好。据我所知,它是在Jet(MS Access数据库引擎)中仅使用SELECT查询后完成的唯一方法。

样品嵌套组解决方案:

ParentID ID Lt Rt RowNumber(Reference) 
Null  1 1 18 0 
1   2 2 13 1 
2   4 3 10 2 
4   3 4 9 3 
3   5 5 6 4 
1   6 14 17 5 
6   7 15 16 6 
2   8 11 12 7 
3   9 7 8 8 

然后拿到ID 2的所有后代:

SELECT * FROM Tbl WHERE Lt Between 2 And 13 

这里的树是什么样子图形:

Modified Preorder Tree

+1

仔细检查后,它看起来像递归查询仅在SQL Server 2005+中可用。 – mwolfe02 2011-03-08 20:05:20

+1

请注意,第一个链接还包括SQL Server中的嵌套集的实现,它将在SQL Server 2000中工作。该链接中的邻接列表示例仅适用于SQL Server 2005+。 – mwolfe02 2011-03-08 20:17:02

+0

该树的图形表示对于理解Rt/Lt数据非常有帮助......但确定数字是在左边还是右边?在你的图形中,你有两个左边的6,左边的8,左边的7,左边的9,...但树无论数字朝哪方都是可以穿越的......尽管Rt/Lt值是不同。 – Matthew 2011-03-08 21:58:42