我有一个表使用Adjacency List模型存储分层信息 . (使用自引用键 - 下面的示例 . 此表可能看起来像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
除了每个节点(不仅是每个叶节点)都有一行外,每一行都是一个"Path"通过层次结构 . category_id列表示当前节点,"lvl"列是其祖先 . 当前节点的值也必须位于最右边的lvl列中 . lvl1列中的值将始终表示根节点,lvl2中的值将始终表示lvl1的直接后代,依此类推 .
如果可能,生成此输出的方法将在SQL中,并且适用于n层层次结构 .
4 回答
在一个简单的邻接列表中进行多级查询总是涉及自左连接 . 制作一个右对齐的表格很容易:
像你的例子一样左对齐它有点棘手 . 想到这一点:
抱歉,在邻接列表模型中无法进行任意深度查询 . 如果您经常进行此类查询,则应将模式更改为other models of storing hierarchical information之一:完全邻接关系(存储所有祖先 - 后代关系),物化路径或嵌套集 .
如果类别不会移动很多(这通常就像你的例子那样的商店),我倾向于嵌套集 .
如前所述,SQL没有干净的方法来实现具有动态变化的列数的表 . 我之前使用的唯一两个解决方案是:1 . 固定数量的自连接,给出固定数量的列(每个BobInce的AS)2 . 在单个列中将结果生成为字符串
第二个听起来很怪诞;将ID存储为字符串?!但是当输出格式化为XML或其他东西时,人们似乎并不介意这么多 .
同样,如果您想要在SQL中加入结果,这几乎没用 . 如果要将结果提供给应用程序,则它可能非常合适 . 但就个人而言,我更喜欢在应用程序而不是SQL中进行展平
我给出了测试代码,但基本方法是以某种方式利用递归;
Scalar Function (something like):
我有一段时间没有使用递归的WITH,但即使我没有SQL来测试任何东西,我也会给出语法 .
Recursive WITH
EDIT - OUTPUT for both is the same:
遍历任意深度的树通常涉及递归过程代码,除非您使用某些DBMS的特殊功能 .
在Oracle中,如果使用邻接列表,CONNECT BY子句将允许您以第一顺序遍历树,就像在此处所做的那样 .
如果使用嵌套集,则左序列号将为您提供访问节点的顺序 .
实际上可以在存储过程中使用动态SQL来完成 . 然后,您将受限于存储过程可以执行的操作 . 显然,将EXEC的结果变成一个临时表而不知道预期有多少列会成为一个挑战 . 但是,如果目标是输出到网页或其他UI,那么可能值得付出努力......