搜索嵌套集

时间:2009-08-16 03:57:32

标签: mysql algorithm search nested-sets

我有一个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是先前找到的类别,但这对我来说似乎不是很有效。有没有更好的方法来搜索嵌套集?

3 个答案:

答案 0 :(得分:1)

我不相信使用嵌套集有一个非常干净和有效的方法。在非规范化列中存储节点祖先的列表可以有效地提供这一点,但我不建议实现它。

虽然有一个ok'ish方法,它是1个查询,并且可以方便地点击你已经拥有的索引。您正在为目标节点的每个深度级别查看一个连接。

对于你的例子foo-bar-baz

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也相当简单。

答案 1 :(得分: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。

答案 2 :(得分:0)

我之前在一个交给我的php项目中看过这个,呃,这很糟糕.. 如果可以,将其分成至少2个表;至少有1个类别和1个项目,所以你可以加入..无论哪种方式你都需要做多个查询我害怕