Я боролся с той же проблемой 10 лет назад.Вот мое личное решение этой проблемы.Но прежде чем я начну объяснять, я хотел бы упомянуть его плюсы и минусы.
Плюсы:
Вы можете выбрать подветвления данного узлав пределах любого количества желаемых глубин с наименьшей из возможных затрат.
То же самое можно сделать, чтобы выбрать родительские узлы.
Нет конкретной СУБДособенность нужна.Таким образом, тот же метод может быть реализован в любом из них.
Все это реализовано с использованием одного поля.
Минусы:
Вы должны быть в состоянии определить максимальное количество глубины для вашего дерева.Вам также необходимо определить максимальное число прямых дочерних элементов для узлов.
Реструктуризация дерева обходится дороже, чем его обход.Но не так дорого, как Модель Nest Set .Добавление новой ветви - это вопрос поиска правильного значения для поля.И чтобы переместить ветку в нового родителя, вам нужно обновить этот узел и все его дочерние элементы (прямые и косвенные).Хорошая новость заключается в том, что удалить узел и его дочерние элементы так же просто, как обойти его (что абсолютно ничего).
Техника:
Рассмотрим следующую таблицу в качестве держателя дерева:
CREATE TABLE IF NOT EXISTS `product_category` (
`product_category_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`category_code` varchar(62) NOT NULL,
PRIMARY KEY (`product_category_id`),
UNIQUE KEY `uni_category_code` (`category_code`)
) DEFAULT CHARSET=utf8 ;
Вся магия совершается в поле category_code
.Вам необходимо закодировать адрес своей ветви в текстовое значение следующим образом:
**node_name -> category_code**
Root -> 01
First child -> 01:01
Second child -> 01:02
First grandchild -> 01:01:01
First child of second child -> 01:02:01
В приведенном выше примере каждый узел может иметь до 99 прямых дочерних элементов (при условии, что мы думаем в десятичном виде).И поскольку category_code
имеет тип varchar(62)
, мы можем иметь глубину (62-2) / 3 = 20.Это компромисс между желаемой глубиной и количеством прямых дочерних элементов, которые может иметь каждый узел, и размером вашего поля.С научной точки зрения, это реализация полного дерева , в котором неиспользуемые ветви фактически не создаются, а зарезервированы.
Хорошие части:
Теперь представьте, что вы хотите выбрать узлы в 01:02
.Вы можете сделать это, используя один запрос:
SELECT *
FROM product_category
WHERE
category_code LIKE '01:02:%'
Выбор прямых узлов под 01:02
:
SELECT *
FROM product_category
WHERE
category_code LIKE '01:02:__'
Выбор всех предков 01:02
:
SELECT *
FROM product_category
WHERE
'01:02' LIKE CONCAT(category_code, ':%')
Плохие части:
Вставка нового узла в дерево - это вопрос поиска правильного category_code
.Это можно сделать с помощью хранимой процедуры или даже на языке программирования, таком как PHP.
Поскольку дерево ограничено по количеству прямых дочерних элементов и глубине, вставка может завершиться неудачно.Но я считаю, что в большинстве практических случаев мы можем принять такое ограничение.
Приветствия.