如何根据树遍历算法从此结果集生成树视图?

时间:2010-09-03 18:29:05

标签: php sql mysql html modified-preorder-tree-t

我有这张桌子:

CREATE TABLE `categories` (
  `id` int(11) NOT NULL auto_increment,
  `category_id` int(11) default NULL,
  `root_id` int(11) default NULL,
  `name` varchar(100) collate utf8_unicode_ci NOT NULL,
  `lft` int(11) NOT NULL,
  `rht` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `category_id` (`category_id`),
  KEY `lft` (`lft`,`rht`),
  KEY `root_id` (`root_id`)
) 

基于这个问题: Getting a modified preorder tree traversal model (nested set) into a <ul>

不同之处在于我在一张桌子上有很多树。每行都有一个代表其父级及其顶级父级的外键:category_id和root_id。我还有基于这个例子的lft和rht字段: http://articles.sitepoint.com/article/hierarchical-data-database/2

基于这些行:

INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14);
INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3);
INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 4, 9);
INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 5, 6);
INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 7, 8);
INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 10, 11);
INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 12, 13);
INSERT INTO `categories` VALUES(8, NULL, NULL, 'Eletronics', 1, 14);
INSERT INTO `categories` VALUES(9, 8, 8, 'Cell Phones', 2, 3);
INSERT INTO `categories` VALUES(10, 8, 8, 'Computers', 4, 9);
INSERT INTO `categories` VALUES(11, 10, 8, 'PC', 5, 6);
INSERT INTO `categories` VALUES(12, 10, 8, 'MAC', 7, 8);
INSERT INTO `categories` VALUES(13, 8, 8, 'Printers', 10, 11);
INSERT INTO `categories` VALUES(14, 8, 8, 'Cameras', 12, 13);

如何构建表示此树的定序列表?

使用sql:

SELECT c. * , (COUNT( p.id ) -1) AS depth
FROM `categorias` AS p
CROSS JOIN categories AS c
WHERE (
c.lft
BETWEEN p.lft
AND p.rht
)
GROUP BY c.id
ORDER BY c.lft;

我得到了这个结果:

alt text

如您所见,我也需要通过root_id进行排序,以便生成正确的树。

此外,在获取树之后,有没有办法按名称命令每个节点?

2 个答案:

答案 0 :(得分:2)

  

如您所见,我也需要通过root_id进行排序,以便生成正确的树。

构建嵌套树模型时,永远不要在lftrgt上复制。实际上,你应该声明它们是唯一的。

在您的数据模型中,类别18的集合重叠。比方说,114同时用于商品18

用以下值替换它们:

INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14);
INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3);
INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 4, 9);
INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 5, 6);
INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 7, 8);
INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 10, 11);
INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 12, 13);
INSERT INTO `categories` VALUES(8, NULL, NULL, 'Eletronics', 15, 29);
INSERT INTO `categories` VALUES(9, 8, 8, 'Cell Phones', 16, 17);
INSERT INTO `categories` VALUES(10, 8, 8, 'Computers', 19, 24);
INSERT INTO `categories` VALUES(11, 10, 8, 'PC', 20, 21);
INSERT INTO `categories` VALUES(12, 10, 8, 'MAC', 22, 23);
INSERT INTO `categories` VALUES(13, 8, 8, 'Printers', 25, 26);
INSERT INTO `categories` VALUES(14, 8, 8, 'Cameras', 27, 28);

现在您无需在root_id订购。

  

此外,在获取树之后,有没有办法按名称命令每个节点?

没有简单的方法,除非您从头开始按名称顺序插入节点。具有较大name的兄弟姐妹应该有更大的lftrgt

INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14);
INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3);
INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 4, 5);
INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 6, 11);
INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 7, 8);
INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 9, 10);
INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 12, 13);

嵌套树只能有一个隐式顺序。

还有一种方法可以在MySQL中查询邻接列表:

但是,如果您想在id以外的任何其他地方订购,则必须创建一个额外的唯一订购列。

您可能还想阅读这篇文章:

显示了如何更有效地存储和查询嵌套集。

答案 1 :(得分:0)

我明白了。

您需要做的就是将root_id设置为顶级父级,以便您可以正确排序。

通过下面的查询,我可以拥有separeted树,并且只提升我正在处理的树:

SELECT c . * , count( p.id ) AS depth
FROM `categories` c
CROSS JOIN categories p
WHERE (
c.lft
BETWEEN p.lft
AND p.rht
)
AND c.root_id = p.root_id
GROUP BY c.id
ORDER BY c.root_id, c.lft