Вопрос списка смежности PHP / MySQL - PullRequest
2 голосов
/ 13 июля 2011

У меня есть следующая проблема: отображение списка смежности, который прошел с рекурсией выходит из sql, как это

SELECT * FROM pages as ps  ORDER BY COALESCE(child_of,page_id), page_id LIMIT x,y

 public static function tree(&$arr, $id = NULL) {

    $result = array();

    foreach ($arr as $a) {

        if ($id == $a['child_of']) {

            $a ['children'] = self::tree($arr, $a['page_id']);

            $result[] = $a;
        }

    }

    return $result;
}

Пока все хорошо - с другим «плющом» я добираюсь туда, где мне нужно быть. Теперь вот трюк, это работает на «разбитых на страницы» результатах, и то, что возможно может случиться (и это происходит), состоит в том, что родитель может быть в одном подмножестве, а ребенок - в другом подмножестве. С рекурсией выше очевидно, что ребенок не доберется до дерева с отсутствующим родителем.

Любые идеи о том, как я могу решить это? Помощь очень ценится.

Ответы [ 2 ]

1 голос
/ 13 июля 2011

Хорошее чтение для начала: Иерархические данные в MySQL (которые я имел обыкновение находить на веб-сайте MySQL.com, arghh)

Читать?

Вот как это можно сделать с помощью модели списка смежности. Но только для известного фиксированного количества вложений (четыре уровня вложенности для этого примера) .

Я бы выяснил, какие из моих страниц являются корневыми (дерева) . Затем выберите только те, которые имеют запрос. Поместите LIMIT x,x в этот оператор выбора.

После этого следующее утверждение: (или что-то подобное)

string query = "
    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 IN('ELECTRONICS', '<some other name>');
";

Может вернуть что-то вроде этого:

+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| 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  |
| etc...      | etc...               | etc...       |       |
+-------------+----------------------+--------------+-------+

Хитрость заключается в том, чтобы использовать только корневые имена запроса с пределом (или идентификаторами, если хотите) в операторе IN() запроса.

Это должно работать довольно неплохо до сих пор (в теории) .

Принцип вышеупомянутого запроса также может быть использован для определения количества потомков в корне дерева (с небольшой магией GROUP BY и COUNT();) Также вы можете выясните, какие из ваших страниц являются корнями с этим принципом (хотя я бы сохранил это в табличных данных для повышения производительности)

Если вы хотите динамическое количество вложений (для почти бесконечного масштабирования) , реализация вложенного набора будет подходящим вариантом.

1 голос
/ 13 июля 2011

Иерархические данные в реляционных таблицах, разве мы все не любим их?

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

Прежде чем спросить, Нет , вам следует не сделать это.

Другой метод, который у вас есть, это выбрать совершенно другую модель для создания вашей иерархии:

  • Вложенные множества
  • Отношения восходящих / потомков между всеми узлами.

См. Слайд 48 и след. здесь .

...