Return all nodes in many-to-many hierarchal tree

扶醉桌前 提交于 2019-12-31 07:25:09

问题


Similar to this question: How do I query for all the nodes between two nodes in a tree?

But I do not have a closure (flattened) table, a child can have many parents, and ID traversal is not necessarily in order. There is no limit to the nesting depth.

Assume a circular reference is impossible... I would like to return all rows required to traverse the hierarchy.

Assume the following table:

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

Given 1 how would I write a single query to return all the rows (get all descendants' relationsips)?

Likewise, given 2 I would expect rows 2,3,4,7,8

Given 6 I would expect rows 6 and 10

An occasional false positive is acceptable as are duplicated rows in the result. A missing row is unacceptable

Implementing in MSAccess and SQL Server 2000+


回答1:


Since you need to model data where nodes can have multiple parents, a nested set/MPTT solution will not work. Another alternative is the use of a closure table.

You would create an additional table that held pairs of items for every ancestor's descendant (and vice versa):

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

Then you would use a join to get the items you need:

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



回答2:


For SQL Server: Adjacency list vs. nested sets: SQL Server

For Jet/MS Access, recursive queries are not an option, so nested sets would be the way to go. For a sample: http://www.mvps.org/access/queries/qry0023.htm

Some background on nested sets:

To implement a nested set solution you would need to add and maintain two additional columns in your table: Lt and Rt(left and right, respectively). You populate these columns by executing a modified preorder tree traversal to assign values to these columns. This can be done most easily with a recursive function. You can then use the left and right values to determine descendants at SELECT time.

The tradeoff is more processing required whenever data is changed but much faster execution when data is retrieved.

The concept is somewhat non-intuitive and certainly has a learning curve, but I have personally used it to great effect. As far as I know, it is the only way to accomplish what you are after using only SELECT queries in Jet (the MS Access db engine).

Sample Nested Set Solution:

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

Then to get all descendants of ID 2:

SELECT * FROM Tbl WHERE Lt Between 2 And 13

Here's what the tree looks like graphically:




回答3:


Check this thread to see if it answers your question using ANSI SQL. Basically Oracle has a nice way to do this using the CONNECT BY clause and you will need to replicate that using ANSI SQL. Simulation of CONNECT BY PRIOR of ORACLE in SQL SERVER



来源:https://stackoverflow.com/questions/5237301/return-all-nodes-in-many-to-many-hierarchal-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!