Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737 Форумы портала PHP.SU :: Вывод дерева MySQL - Closure Table
Покинул форум
Сообщений всего: 356
Дата рег-ции: Июнь 2013 Откуда: Ставропольский край
Помог: 10 раз(а)
[+]
Что-то я не могу никак отдуплить. Если для хранения дерева в MYSQL таблице используется метод Closure Table, то как можно вывести все дерево с сохранением структуры.
Ну допустим я хочу построить дерево категорий в форме в виде checkbox.
Вывести потомков или предков одной категории - не проблема. Но как вытащить все дерево и правильно его построить? (Добавление)
На ум приходит только одно решение - сделать еще одну табличку
----- ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
Мелкий
Отправлено: 25 Апреля, 2014 - 09:37:20
Активный участник
Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009 Откуда: Россия, Санкт-Петербург
Помог: 618 раз(а)
Hapson, да, точно, двух полей достаточно. Неправильно понял идею самой closure table (как, наверное, уже понятно - всерьёз я эту схему не изучал, по теме вопроса не подскажу).
----- PostgreSQL DBA
esterio
Отправлено: 25 Апреля, 2014 - 10:37:29
Активный участник
Покинул форум
Сообщений всего: 5025
Дата рег-ции: Нояб. 2012 Откуда: Украина, Львов
SELECT*FROM closure_table WHERE parent=X GROUPBY parent HAVING COUNT(1)=1
- Выбрать узлы, которые будут иметь в родителях X, а в качестве потомков - найденные листья. Это будет запрос на WHERE IN .. - что хорошо выполнится через range scan. Найденные узлы нужно рассортировать по листьям, поскольку нужно строить дерево и просто уровня уже недостаточно. Это, скорее всего, будет поручено приложению.
- Повторить до тех пор, пока есть записи.
В общем-то, запросов будет не так и много, но всё же запрос не будет один (несмотря на то, что всё дерево можно получить одним запросом).
Альтернатива - которой я бы рекомендовал пользоваться - выбрать всё дерево, а затем отдельно, в приложении, разбирать его. Это, конечно, потребует правильного построения массива, но все же это не так сложно. Этим можно воспользоваться, если размер данных не слишком велик.
Так как построение дерева "с листьев" - в общем-то, не очень простая задача, то можно хранить длину пути, чтобы получить возможность строить дерево с корня.
Ниже приведу пример, как можно поступить в случае с приложением. Вообще говоря, нам вовсе не обязательно хранить уровень - его можно вычислить (однако, как правило, лучше хранить и пересчитывать, так как вычисляется он исходя из количества записей в child-поле для конкретного узла). В примере я так и поступлю - то есть, не буду хранить уровень отдельно. Предположим, у нас есть дерево:
- я записываю его напрямую, но ничто не мешает выбирать данные из БД. Тогда в приложении мы можем рекурсивно собрать данные в привычную структуру со смежными подчинёнными узлами. Для этого нужно построить индекс-таблицу, в которой будет считаться как уровень узла, так и храниться его связи с остальными. В моём примере индекс двунаправленный (родители -> потомки, потомки->родители):
-выношу это отдельно, так как понимание структуры этой вспомогательной индекс-таблицы очень важно. По сути, работая с индексированной таблицей в СУБД будет выполняться примерно та же работа. Использовать это можно так:
- то есть, проверить, не лист ли передан, и, если нет, пройтись по поддереву рекурсивно. Поддерево - это все подчинённые узлы, у которых уровень на +1 больше. На этом всё.
Здесь видимо напутал.
Для S будет одна запись - S | S
И S будет в потомках P R T
Я думаю проще ввести еще одну таблицу, где хранить первого родителя. То есть совместить таблицу связей со списком смежностей. По первому родителю легко построить дерево. Выборка за один запрос. Вобщем вот такая идея хороша https://coderwall[dot]com/p/lixing
Я так думаю
----- ПЫХ тут - ходи туда, прежде чем писать сюда (толку больше будет)
EuGen
Отправлено: 25 Апреля, 2014 - 17:27:19
Профессионал
Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007 Откуда: Berlin
Помог: 707 раз(а)
В первом листинге - да, названия должны быть обратными. Всё дерево и так выбирается одним запросом. Но если нужно именно строить его где-либо для рекурсивных процедур, то - как я уже и указал выше - либо начинать с листьев, либо хранить/вычислять уровни. Второе мне кажется наилучшим вариантом.
При этом я всё ещё рекомендую форматирование поручать приложению, так как это именно его работа. Выбрать через СУБД - можно, однако пользы в этом почти что нет. Тем более, что при двойной индексации выбранного дерева в приложении операции будут происходить очень быстро (так как мы используем хеш-выборки)
----- Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.