Как создать представление дерева из этого набора результатов на основе алгоритма обхода дерева? - PullRequest
7 голосов
/ 03 сентября 2010

У меня есть эта таблица:

CREATE TABLE `categories` (
  `id` int(11) NOT NULL auto_increment,
  `category_id` int(11) default NULL,
  `root_id` int(11) default NULL,
  `name` varchar(100) collate utf8_unicode_ci NOT NULL,
  `lft` int(11) NOT NULL,
  `rht` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `category_id` (`category_id`),
  KEY `lft` (`lft`,`rht`),
  KEY `root_id` (`root_id`)
) 

На основании этого вопроса: Получение модифицированной модели обхода дерева предзаказа (вложенный набор) в

    Разница в том, что у меня много деревьев в одной таблице.У каждой строки есть внешний ключ, представляющий ее родителя и его верхнего родителя: category_id и root_id.Также у меня есть поля lft и rht, основанные на этом примере: http://articles.sitepoint.com/article/hierarchical-data-database/2

    На основе этих строк:

    INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14);
    INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3);
    INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 4, 9);
    INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 5, 6);
    INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 7, 8);
    INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 10, 11);
    INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 12, 13);
    INSERT INTO `categories` VALUES(8, NULL, NULL, 'Eletronics', 1, 14);
    INSERT INTO `categories` VALUES(9, 8, 8, 'Cell Phones', 2, 3);
    INSERT INTO `categories` VALUES(10, 8, 8, 'Computers', 4, 9);
    INSERT INTO `categories` VALUES(11, 10, 8, 'PC', 5, 6);
    INSERT INTO `categories` VALUES(12, 10, 8, 'MAC', 7, 8);
    INSERT INTO `categories` VALUES(13, 8, 8, 'Printers', 10, 11);
    INSERT INTO `categories` VALUES(14, 8, 8, 'Cameras', 12, 13);
    

    Как мне создать список с порядковыми номерами, представляющий это дерево?

    С приведенным ниже sql:

    SELECT c. * , (COUNT( p.id ) -1) AS depth
    FROM `categorias` AS p
    CROSS JOIN categories AS c
    WHERE (
    c.lft
    BETWEEN p.lft
    AND p.rht
    )
    GROUP BY c.id
    ORDER BY c.lft;
    

    Я получил такой результат:

    alt text

    Как видите, мне нужно сделать заказ и по root_id,чтобы я мог сгенерировать правильное дерево.

    Также, после получения дерева, есть ли способ упорядочить каждый узел по имени?

    Ответы [ 2 ]

    2 голосов
    / 04 сентября 2010

    Как видите, мне нужно упорядочить по root_id, чтобы я мог сгенерировать правильное дерево.

    При построении модели с вложенным деревом никогда не делайте дубликаты на lft и rgt. На самом деле, вы должны объявить их уникальными.

    В вашей модели данных наборы для категорий 1 и 8 перекрываются. Скажем, от 1 до 14 используются как для предметов 1, так и 8.

    Заменить их следующими значениями:

    INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14);
    INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3);
    INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 4, 9);
    INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 5, 6);
    INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 7, 8);
    INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 10, 11);
    INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 12, 13);
    INSERT INTO `categories` VALUES(8, NULL, NULL, 'Eletronics', 15, 29);
    INSERT INTO `categories` VALUES(9, 8, 8, 'Cell Phones', 16, 17);
    INSERT INTO `categories` VALUES(10, 8, 8, 'Computers', 19, 24);
    INSERT INTO `categories` VALUES(11, 10, 8, 'PC', 20, 21);
    INSERT INTO `categories` VALUES(12, 10, 8, 'MAC', 22, 23);
    INSERT INTO `categories` VALUES(13, 8, 8, 'Printers', 25, 26);
    INSERT INTO `categories` VALUES(14, 8, 8, 'Cameras', 27, 28);
    

    Теперь вам не нужно заказывать на root_id.

    Также, после получения дерева, есть ли способ упорядочить каждый узел по имени?

    Нет простого способа, если только вы не вставите узлы в порядке имен с начала. У братьев и сестер с большим name должно быть больше lft и rgt:

    INSERT INTO `categories` VALUES(1, NULL, NULL, 'Fruits', 1, 14);
    INSERT INTO `categories` VALUES(2, 1, 1, 'Apple', 2, 3);
    INSERT INTO `categories` VALUES(7, 1, 1, 'Banana', 4, 5);
    INSERT INTO `categories` VALUES(3, 1, 1, 'Orange', 6, 11);
    INSERT INTO `categories` VALUES(4, 3, 1, 'Orange Type 1', 7, 8);
    INSERT INTO `categories` VALUES(5, 3, 1, 'Orange Type 2', 9, 10);
    INSERT INTO `categories` VALUES(6, 1, 1, 'Pear', 12, 13);
    

    Вложенное дерево может иметь только один неявный порядок.

    Существует также способ запроса списка смежности в MySQL:

    , однако вам придется создать дополнительный уникальный столбец заказа, если вы хотите заказать что-либо еще, кроме id.

    Вы также можете прочитать эту статью:

    , который показывает, как более эффективно хранить и запрашивать вложенные множества.

    0 голосов
    / 06 сентября 2010

    Я понял.

    Все, что вам нужно сделать, это установить root_id и для старших родителей, чтобы вы могли правильно ЗАКАЗАТЬ.

    С помощью приведенного ниже запроса я могу разделить деревья и заменить только дерево, над которым я работаю:

    SELECT c . * , count( p.id ) AS depth
    FROM `categories` c
    CROSS JOIN categories p
    WHERE (
    c.lft
    BETWEEN p.lft
    AND p.rht
    )
    AND c.root_id = p.root_id
    GROUP BY c.id
    ORDER BY c.root_id, c.lft
    
    Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
    ...