Двухуровневое дерево MySQL + PHP

Немного хотелось бы описать процесс хранения двухуровневого дерева в MySQL, а так же его выгрузку одним запросом и формирование PHP массива для отображения в шаблоне и т.д.

Начну с структуры таблицы MySQL, на примере таблицы для хранения тегов Категория -> Тег.

Структура таблицы
CREATE TABLE table_tag (
  tag_id int(11) NOT NULL AUTO_INCREMENT COMMENT 'ИД тега',
  tag_name varchar(50) NOT NULL COMMENT 'ИМЯ тега',
  tag_type enum ('part', 'tag') NOT NULL DEFAULT 'tag' COMMENT 'ТИП тега',
  tag_parent int(10) UNSIGNED DEFAULT NULL COMMENT 'ИД родителя',
  PRIMARY KEY (tag_id),
  INDEX IDX_tag_parent (tag_parent),
  INDEX IDX_tag_type (tag_type)
)
ENGINE = MYISAM
COMMENT = 'Таблицы тегов';

Заполнение данными
Естественно, что заполнение данными для каждого конкретного случая будет если не уникально, то как минимум, отличаться. В данном случае, я буду использовать часть данных тегов уже существующего проекта.

Для примера, возьмём родителя «Животные» и элементы 'Кошки', 'Собаки', 'Лошади'.
INSERT INTO table_tag (tag_id, tag_name, tag_type, tag_parent) VALUES
(46, 'Животные', 'part', 0);
INSERT INTO table_tag (tag_id, tag_name, tag_type, tag_parent) VALUES
(51, 'Кошки', 'tag', 46);
INSERT INTO table_tag (tag_id, tag_name, tag_type, tag_parent) VALUES
(52, 'Собаки', 'tag', 46);
INSERT INTO table_tag (tag_id, tag_name, tag_type, tag_parent) VALUES
(53, 'Лошади', 'tag', 46);

Запрос к базе, для загрузки двухуровневого дерева тегов
Смысл этой статьи, сохранить в своей памяти алгоритм загрузки двухуровневого дерева одним запросом, так что перехожу непосредственно к запросу. Он будет такой:
SELECT
  SubQuery.tag_id AS parentID,
  SubQuery.tag_name AS parentName,
  table_tag.tag_id,
  table_tag.tag_name
FROM table_tag
  RIGHT OUTER JOIN (SELECT
	  table_tag.tag_name,
	  table_tag.tag_id,
	  table_tag.tag_type
	FROM table_tag
	WHERE table_tag.tag_type = 'part') SubQuery
	ON table_tag.tag_parent = SubQuery.tag_id
ORDER BY parentName, table_tag.tag_name

Результатом выполнения запроса будет табличный массив, в котором каждой строке будет соответствовать:
  • ИД родительской категории
  • Имя родительской категории
  • ИД тега
  • Имя тега

Категории, у которых нет вложенных элементов (тегов), попадут в таблицу только один раз. В зависимости от задачи, можно будет исключить их из конечного результата, или оставить.

Формирование массива PHP, для использование в шаблоне и т.д.
Единственное, на что хочется обратить внимание в данном разделе, так это то, что для исключения из выборки пустых результатов, нужно добавить дополнительное условие в цикл обработки.
// массив результатов
$tags = array();

// цикл обработки данных, полученных от сервера MySQL ($rawTags - табличный массив, описанный в статье ранее)
foreach ($rawTags as $tag) {
	if (!empty($tag['tag_id'])) { // условие для исключения пустых результатов
		// добавление в массив результатов, пары (tag_id, tag_name), с ключом $tag['parentName'] - имя родительского элемента
                $tags[$tag['parentName']][] = array(
			'tag_name' => $tag['tag_name'],
			'tag_id'   => $tag['tag_id']
		);
	}
}

Результатом работы скрипта будет массив:
array(
    'Животные'=>array(
        [0]=>array(
            'tag_name' => 'Кошки'
            'tag_id'   => 51
        )// ... и далее, для остальных элементов
    )
)

Use this ;)
  • +1
  • 24 февраля 2015, 11:29
  • igorrius

Комментарии (0)

RSS свернуть / развернуть
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
comments powered by Disqus