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

4

3 回答 3

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

于 2009-08-16T04:44:24.663 回答
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;

-阿尔。

于 2009-08-16T08:01:58.493 回答
0

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

于 2009-08-16T04:16:29.270 回答