Как получить структурированный результат, используя вложенный набор в MySQL и PHP? - PullRequest
11 голосов
/ 07 апреля 2010

Нет ограничений по глубине.

Как получить структурированную ветку или даже целое дерево?

Определение отсюда: Управление иерархическими данными в MySQL

Ответы [ 5 ]

5 голосов
/ 31 августа 2012

Я не уверен, что это именно то, о чем вы просите, но стоит отметить, что вы можете получить все дерево, по одной строке на путь, каждый путь в виде строки, как это чисто в MySQL, используя GROUP_CONCAT и расширение примера «Извлечение одного пути» из http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

SELECT 
  GROUP_CONCAT(parent.name ORDER BY parent.lft ASC SEPARATOR '|') 
FROM nested_category AS node
     CROSS JOIN nested_category AS parent 
WHERE 
  node.lft BETWEEN parent.lft AND parent.rgt 
GROUP by node.id 
ORDER BY node.lft;

Это выведет пути для каждого узла в дереве.

Обратите внимание, что nested_category AS node CROSS JOIN nested_category AS parentэквивалентно nested_category AS node, nested_category AS parent.

При этом в качестве разделителя используется строка '|', если вы хотите разбить ее на массив элементов пути и знаете, что в ваших данных есть строка, которую вы не можете указатьэто вместо этого.

2 голосов
/ 10 апреля 2010

Я использую похожий, но не совсем тот же подход, который также сохраняет ссылку на родителя у ребенка; это облегчает построение древовидной структуры из данных. Если это полезно, я могу опубликовать код для извлечения данных в дерево на PHP.

@ Marc, описанная структура данных не обязательно для выполнения операций над множествами; это просто облегчает работу со структурой. Если вы хотите получить целое дерево данных, и каждая запись просто хранит указатель на родительскую запись, то вам нужно рекурсивно запросить базу данных, чтобы получить полное дерево данных. Если вы используете описанный там подход, то вы можете извлечь весь набор одним запросом.

Редактировать: вот код, который строит древовидную структуру, ЕСЛИ вы поддерживаете дочернюю -> родительскую ссылку, а также lft / right. Я предпочитаю делать это, потому что на самом деле это все еще быстрее, если вы хотите получить только прямые потомки одного уровня дерева.

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

  • Порядок запроса "lft ASC", таким образом вы всегда будете обрабатывать родительский узел перед его дочерними элементами.
  • Сохранить ссылку на каждый узел по идентификатору; таким образом, любой дочерний элемент этого узла может легко найти его и добавить себя в родительский.
  • Итерация по результатам, сохранение ссылки для каждого по идентификатору (как указано выше) и добавление этого узла к дочерним элементам его родителя.

В любом случае, вот код -

<?php
$children = mysql_query('SELECT * FROM nested_category ORDER BY lft ASC');

/* Get the first child; because the query was ordered by lft ASC, this is
   the "root" of the tree */
$child          = mysql_fetch_object($children);
$root           = new StdClass;
$root->id       = $child->folderID;
$root->children = array();
/* Store a reference to the object by the id, so that children can add
   themselves to it when we come across them */
$objects        = array($root->id => $root);

/* Build a tree structure */
while ($child = mysql_fetch_object($children)) {
    /* Create a new wrapper for the data */
    $obj           = new StdClass;
    $obj->id       = $child->id;
    $obj->children = array();
    /* Append the child to the parent children */
    $parent = $objects[$child->parent];
    $parent->children[] = $obj;
    $objects[$obj->id] = $obj;
}   
0 голосов
/ 15 апреля 2010

Я должен сообщить вам о методе, с помощью которого вы можете работать с древовидными структурами, используя php .. без рекурсии.Я думаю, что вы очень хорошо знакомы со стандартной библиотекой php (SPL).Вы можете использовать итераторы для вашего вопроса.

http://www.php.net/~helly/php/ext/spl/

вот ссылка на документацию по SPL.Вот несколько решений для вашего примера ссылки Mysql: - Просто извлекая свой массив из таблицы, вы можете работать с ними и отображать его как преференцию

Для: - Модель списка смежности

Выможно использовать «RecursiveIteratorIterator», который покажет все результаты, включая все дочерние элементы.

Если вы хотите показать только дочерние элементы.Вы можете использовать "ParentIterator"

0 голосов
/ 12 апреля 2010

Глядя на вашу ссылку, я бы сделал это с помощью Left Joins. Посмотрите на пример получения полного дерева.

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4 FROM category AS t1 LEFT JOIN category AS t2 ON t2.parent = t1.category_id LEFT JOIN category AS t3 ON t3.parent = t2.category_id LEFT JOIN category AS t4 ON t4.parent = t3.category_id WHERE t1.name = 'ELECTRONICS';

Вам потребуется ЛЕВОЕ СОЕДИНЕНИЕ для каждого иерархического уровня, который вы хотите включить. Затем результат может быть проанализирован php в любую желаемую структуру данных. Просто игнорируйте NULL результаты.

| ELECTRONICS | TELEVISIONS | TUBE | NULL |

| ELECTRONICS | TELEVISIONS | LCD | NULL |

| ELECTRONICS | TELEVISIONS | PLASMA | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |

| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL |

Если у вас есть глубокая структура, это будет худший метод, потому что MySQL Joins требуется много времени для выполнения, когда нужно объединить много таблиц.

Надеюсь, я не понял вашего вопроса.

0 голосов
/ 07 апреля 2010

Даже если структура данных на стороне mysql несколько экзотическая, данные все равно извлекаются с использованием обычных методов запросов. Выполните соответствующий оператор select, зациклите результаты и поместите его в массив PHP. Хотя я не знаю, зачем вам это нужно, поскольку в PHP было бы гораздо сложнее выполнять операции над множествами, чем в MySQL.

...