Я хотел бы выбрать корневой элемент, и его дети будут максимально эффективными. Я предпочитаю использовать модель вложенных множеств, но на этот раз структура таблицы следует за моделью смежности . Подробнее о вложенных наборах и модели соответствия .
У меня есть dependencies-table
items-table
.
Таблица зависимостей
dependency_id | item_id | child_id 1 | 1 | 4 2 | 2 | 5 3 | 4 | 7 4 | 7 | 3 5 | 9 | 3 6 | 1 | 2
Таблица элементов
item_id | name | info 1 | Item A | 1st Item 2 | Item D | 2nd Item 3 | Item C | 3rd Item 4 | Item D | 4th Item 5 | Item E | 5th Item 6 | Item F | 6th Item
SQL, сначала попробуйте
# selecting children (non-recursive) # result: 4, 2 SELECT child_id AS id FROM `dependencies_table` WHERE item_id = 1
Мне нужен этот SELECT рекурсивный.
Желаемый выход
# children of item #1 dependency_id | item_id | child_id 1 | 1 | 4 // 1st level 6 | 1 | 2 // 1st level 2 | 2 | 5 // 2nd level, 1->2->5
Этот случай должен быть очень распространенным явлением, но мне интересно, что я пока не нашел лучшей практики. Обратите внимание: это MySQL, поэтому я не могу использовать CTE !
Как бы вы решили эту проблему? Заранее спасибо!
Редактировать: я нашел интересную тему , но моя проблема еще не решена. Поэтому, пожалуйста, не закрывайте этот вопрос.
Редактировать 2: Вот интересное решение для PHP , но, к сожалению, не то, что я действительно хочу.
Как человек NoSQL я должен сказать, для чего нужны графики. Но да, я понимаю. Есть причины для использования SQL, но этот конкретный пример – это просто не то, для чего созданы эти базы данных, особенно когда вы можете иметь n уровень детей, который mysql будет выполнять крайне медленно, на самом деле есть запрос для этого, даже для n уровней, но это какое-то сумасшедшее дерьмо. (что-то около 42 Внутренних объединений, если я правильно помню)
Так что да, вы хотите забрать столы и сделать материал для детей в php.
Вот как вы получите свой результат в php, как только вы выберете всю таблицу зависимостей,
$dep = array(); $dep[] = array('item_id' =>'1', 'child_id' =>'4'); $dep[] = array('item_id' =>'2', 'child_id' =>'5'); $dep[] = array('item_id' =>'4', 'child_id' =>'7'); $dep[] = array('item_id' =>'7', 'child_id' =>'3'); $dep[] = array('item_id' =>'9', 'child_id' =>'3'); $dep[] = array('item_id' =>'1', 'child_id' =>'2'); function getchilds($dependencies, $id) { $ref = array(); foreach($dependencies as $dep){ $item_id = $dep['item_id']; $child = $dep['child_id']; if(!is_array($ref[$item_id])) $ref[$item_id] = array('id' => $item_id); if(!is_array($ref[$child])) $ref[$child] = array('id' => $child); $ref[$item_id]['children'][] = &$ref[$child]; } return $ref[$id]; } getchilds($dep,1);
Это использует ссылки, чтобы проходить через каждый элемент только один раз, я не могу изобразить что-либо более сильное, и оно работает для бесконечного количества уровней. На самом деле, я уверен, что это быстрее, чем любой SQL Query для фиксированного количества уровней.
для первого элемента это в основном даст вам
1 - 2 - 5 \ 4 - 7 - 3
Oracle позволяет использовать иерархические запросы с помощью CONNECT BY PRIOR
, но это не поддерживается в MySQL. Таким образом, это лучше всего реализовать на языке программирования .
Тем не менее, если вы должны сделать это в SQL и принять фиксированную глубину рекурсии, вы можете использовать беспорядочный набор self-соединений с UNION
. Например, это повторяет три уровня:
SELECT a.child_id FROM dependencies_table a WHERE a.item_id = '1' UNION SELECT b.child_id FROM dependencies_table a JOIN dependencies_table b ON (a.child_id = b.item_id) WHERE a.item_id = '1' UNION SELECT c.child_id FROM dependencies_table a JOIN dependencies_table b ON (a.child_id = b.item_id) JOIN dependencies_table c ON (b.child_id = c.item_id) WHERE a.item_id = '1'
Удовлетворяя следующие результаты как элементы, которые в некотором смысле являются зависимостями пункта 1:
4 2 5 7 3
SQL Fiddle