2009-08-16 131 views
1

我有一个MySQL表,其行为像一个嵌套集以包含类别的层次结构。该表的模式是这样的:搜索嵌套集

CREATE TABLE IF NOT EXISTS `categories` (
    `id` int(11) NOT NULL auto_increment, 
    `name` varchar(200) NOT NULL, 
    `parent_id` int(11) default NULL, 
    `lft` int(11) default NULL, 
    `rgt` int(11) default NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `index_categories_on_parent_id_and_name` (`parent_id`,`name`) 
) 

lftrgt定义节点(一组嵌套的工作原理是,每个节点的ID属于母公司的边界内的方式)的左右边界,并parent_id指定的父节点。唯一索引允许有多个具有相同名称的类别,只要它们不具有相同的父级。

我想找出一个适当的方法来找到集合中的特定节点,根据层次结构。例如,如果我查找foo/bar/baz,我想要检索名为baz的父节点名为bar的节点,其父节点名为foo。很显然,我不能只按名称搜索,因为可能会有多个具有相同名称的类别。

我能想到这样做的方法是找到最上面的类别,然后找到每个后续类别,其中父母id是先前找到的类别的给定名称,但这对我来说似乎不是很有效。有没有更好的方法来搜索嵌套集?

回答

1

我不相信有一个完全清洁和有效的方式用嵌套集合来做到这一点。将非结构化列中的节点祖先列表存储起来可以提供这种效率,但我不建议实现它。

虽然有一个好的方法,这是一个查询,并将方便地击中您已有的索引。您正在查看目标节点的每个深度级别的一个连接。

对于示例FOO酒吧巴兹

select c3.*
from categories c1
inner join categories c2 on c2.parent_id = c1.id AND c2.name = 'bar'
inner join categories c3 on c3.parent_id = c2.id AND c2.name = 'baz'
where c1.name = 'foo'

这不是最大的,但除非你想去存储一堆非规格化信息的努力,它可能是你最好的选择。在代码中生成SQL也是相当直接的。

0

我以前在一个交给我的php项目中看到过这个,呃,这真是太糟糕了。如果可以的话,至少分成两张表;至少有1个类别和1个项目,所以你可以加入..无论哪种方式,你将需要做多个查询恐怕

+0

我不认为你完全明白这个问题;我确实有类别和项目的单独表格,但我不关心这里的项目。我只想根据给定的层次结构获取特定类别的ID。 – 2009-08-16 04:29:57

1
TopVar = 'foo' 
MidVar = 'bar' 
BotVar = 'baz' 

SELECT D0.* 
FROM categories D0, categories D1, categories D2 
WHERE D0.name = :BotVar 
    AND D0.lft > D1.lft 
    AND D0.rgt < D1.rgt 
    AND D1.name = :MidVar 
    AND D1.lft > D2.lft 
    AND D1.rgt < D2.rgt 
    AND D2.name = :TopVar; 

-Al。

+0

小技巧,带我waaaaaaay太长时间工作与嵌套设置。 要查找节点的后代,只能引用查询中的'lft'列。如果您点击左侧和右侧列,您的查询将包含两个范围条件(这是有点优化阻力)。如果仅指左侧,则它将是单个范围条件,可以通过lft上的索引完全覆盖。 可以说我们想要节点A的后代已经离开了12和右侧155: select * from categories c where c.lft between 12 and 155 Michael 2009-08-18 01:01:23