将邻接列表层次结构展平为所有路径的列表
我有一个使用邻接列表模型存储层次结构信息的表。 (使用自引用键 - 下面的示例。此表可能看起来熟悉):
category_id name parent
----------- -------------------- -----------
1 ELECTRONICS NULL
2 TELEVISIONS 1
3 TUBE 2
4 LCD 2
5 PLASMA 2
6 PORTABLE ELECTRONICS 1
7 MP3 PLAYERS 6
8 FLASH 7
9 CD PLAYERS 6
10 2 WAY RADIOS 6
将上述数据“扁平化”为类似这样的数据的最佳方法是什么?
category_id lvl1 lvl2 lvl3 lvl4
----------- ----------- ----------- ----------- -----------
1 1 NULL NULL NULL
2 1 2 NULL NULL
6 1 6 NULL NULL
3 1 2 3 NULL
4 1 2 4 NULL
5 1 2 5 NULL
7 1 6 7 NULL
9 1 6 9 NULL
10 1 6 10 NULL
8 1 6 7 8
每一行都是层次结构中的一个“路径”,除了每个节点都有一行< /em> (不仅仅是每个叶节点)。 Category_id 列表示当前节点,“lvl”列是其祖先。 当前节点的值也必须位于最右侧的 lvl 列中。 lvl1 列中的值将始终表示根节点,lvl2 中的值将始终表示 lvl1 的直接后代,依此类推。
如果可能的话,生成此输出的方法将采用 SQL,并且适用于 n 层层次结构。
I have a Table that stores Hierarchical information using the Adjacency List model. (uses a self referential key - example below. This Table may look familiar):
category_id name parent
----------- -------------------- -----------
1 ELECTRONICS NULL
2 TELEVISIONS 1
3 TUBE 2
4 LCD 2
5 PLASMA 2
6 PORTABLE ELECTRONICS 1
7 MP3 PLAYERS 6
8 FLASH 7
9 CD PLAYERS 6
10 2 WAY RADIOS 6
What is the best method to "flatten" the above data into something like this?
category_id lvl1 lvl2 lvl3 lvl4
----------- ----------- ----------- ----------- -----------
1 1 NULL NULL NULL
2 1 2 NULL NULL
6 1 6 NULL NULL
3 1 2 3 NULL
4 1 2 4 NULL
5 1 2 5 NULL
7 1 6 7 NULL
9 1 6 9 NULL
10 1 6 10 NULL
8 1 6 7 8
Each row is one "Path" through the Hierarchy, except there is a row for each node (not just each leaf node). The category_id column represents the current node and the "lvl" columns are its ancestors. The value for the current node must also be in the farthest right lvl column. The value in the lvl1 column will always represent the root node, values in lvl2 will always represent direct descendants of lvl1, and so on.
If possible the method to generate this output would be in SQL, and would work for n-tier hierarchies.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
要跨简单的邻接表进行多级查询总是涉及自左连接。 制作右对齐表格很容易:
像您的示例一样将其左对齐有点棘手。 我想到了这一点:
抱歉,在邻接表模型中不可能进行任意深度查询。 如果您经常进行这种查询,则应该将架构更改为 存储层次信息的其他模型:完全邻接关系(存储所有祖先-后代关系)、物化路径或嵌套集。
如果类别不经常移动(对于像您的示例这样的商店通常是这种情况),我会倾向于嵌套集。
To do multi-level queries across a simple adjacency-list invariably involves self-left-joins. It's easy to make a right-aligned table:
To left-align it like your example is a bit more tricky. This comes to mind:
Sorry, arbitrary-depth queries are not possible in the adjacency-list model. If you are doing this kind of query a lot, you should change your schema to one of the other models of storing hierarchical information: full adjacency relation (storing all ancestor-descendent relationships), materialised path, or nested sets.
If the categories don't move around a lot (which is usually the case for a store like your example), I would tend towards nested sets.
如前所述,SQL 没有干净的方法来实现具有动态变化列数的表。 我之前使用过的唯一两种解决方案是:
1. 固定数量的自连接,给出固定数量的列(AS per BobInce)
2. 将结果生成为单列中的字符串
第二个听起来很奇怪; 将 ID 存储为字符串?! 但当输出被格式化为 XML 或其他格式时,人们似乎不太介意。
同样,如果您随后想要在 SQL 中连接结果,则这几乎没有什么用处。 如果要将结果提供给应用程序,它可能非常合适。 然而,就我个人而言,我更喜欢在应用程序中进行扁平化,而不是 SQL
我被困在一个 10 英寸的屏幕上,无法访问 SQL,所以我无法给出经过测试的代码,但基本方法是以某种方式利用递归;
- 递归标量函数可以做到这一点
- MS SQL 可以使用递归WITH语句来做到这一点(更高效)
标量函数(类似):
我已经有一段时间没有使用递归WITH了,但我会尝试一下语法即使我这里没有 SQL 来测试任何东西:)
递归使用
编辑 - 两者的输出相同:
As mentioned, SQL has no clean way to implement tables with dynamically varying numbers of columns. The only two solutions I have used before are:
1. A fixed number Self-Joins, giving a fixed number of columns (AS per BobInce)
2. Generate the results as a string in a single column
The second one sounds grotesque initially; storing IDs as string?! But when the output is formatted as XML or something, people don't seem to mind so much.
Equally, this is of very little use if you then want to join on the results in SQL. If the result is to be supplied to an Application, it Can be very suitable. Personally, however, I prefer to do the flattening in the Application rather than SQL
I'm stuck here on a 10 inch screen without access to SQL so I can't give the tested code, but the basic method would be to utilise recursion in some way;
- A recursive scalar function can do this
- MS SQL can do this using a recursive WITH statement (more efficient)
Scalar Function (something like):
I haven't used a recursive WITH in a while, but I'll give the syntax a go even though I don't have SQL here to test anything :)
Recursive WITH
EDIT - OUTPUT for both is the same:
遍历任意深度的树通常涉及递归过程代码,除非您利用某些 DBMS 的特殊功能。
在 Oracle 中,如果您使用邻接列表,则 CONNECT BY 子句将允许您以深度优先顺序遍历树,就像您在此处所做的那样。
如果您使用嵌套集,左侧的序列号将为您提供访问节点的顺序。
Traversing a tree of arbitrary depth generally involves recursive procedural code, unless you make use of the special features of some DBMS.
In Oracle, the CONNECT BY clause will permit you to traverse the tree in depth first order if you use adjacency list, as you did here.
If you use nested sets, the left sequence number will provide you with the order to visit the nodes.
实际上可以在存储过程中使用动态 SQL 来完成。 然后,您将受限于存储过程可以完成的操作。 显然,在不知道需要多少列的情况下将结果执行到临时表中是一个挑战。 但是,如果目标是输出到网页或其他 UI,那么可能值得付出努力......
Actually can be done with dynamic SQL within a stores procedure. You then become limited to what can be done sith the stored procedure. Obviously it becomes a challenge to EXEC the results into a temporary table not knowing how many columns to expect. However, if the goal is to output to a web page or other UI then it may be worth the effort...