Обратите внимание на то, что если удалить строки в TreePaths, то сами комментарии при этом не удаляются. Это кажется странным для данного примера Comments, но такая политика не лишена смысла при работе с другими типами деревьев, например категориями в каталоге изделий или служащими в структурной схеме организации. Не обязательно требуется удалять узел, когда изменяют его взаимосвязи с другими узлами. Хранение путей в отдельной таблице обеспечивает более гибкое выполнение этой задачи.
Чтобы переместить поддерево из одного местоположения на дереве в другое, сначала отсоедините поддерево от его предков, удалив строки, которые ссылаются на предков верхнего узла в этом поддереве и потомков этого узла. Например, чтобы переместить комментарий № 6 из его позиции в качестве дочернего элемента комментария № 4 в дочерний элемент комментария № 3, начните со следующего удаления. Убедитесь, что не удаляется ссылка комментария № 6 на самого себя.
Файл npvtmpa\Trees/soln/closure-table/move-subtree.sql
DELETE FROM TreePaths
WHERE descendant IN (SELECT descendant FROM TreePaths WHERE ancestor = 6)
AND ancestor IN (SELECT ancestor FROM TreePaths WHERE descendant = 6 AND ancestor != descendant);
При выборе предков комментария № 6, но не самого комментария № 6 и потомков комментария № 6, включая комментарий № 6, удаляются корректно все пути от предков комментария № 6 до комментария № 6 и его потомки. Другими словами, с помощью этого кода удаляются пути (1, 6), (1, 7), (4, 6) и (4, 7). При этом пути (6,6) и (6, 7) не удаляются.
Затем добавьте осиротевшее поддерево путем вставки строк, соответствующих предкам нового местоположения и потомкам поддерева. Можно использовать синтаксис CROSS JOIN, чтобы создать декартово произведение, генерирующее строки, необходимые для сопоставления предков нового местоположения со всеми узлами в поддереве, которое требуется переместить.
Файл примера: Trees/soln/closure-table/move-subtree.sql
INSERT INTO TreePaths (ancestor, descendant)
SELECT supertree.ancestor, subtree.descendant FROM TreePaths AS supertree
CROSS JOIN TreePaths AS subtree WHERE supertree.descendant = 3
AND subtree.ancestor = 6;
Данный программный фрагмент создает новые пути, используя предков комментария № 3, включая сам комментарий № 3, и потомков комментария № 6, включая комментарий № 6. Таким образом, новыми путями являются (1, 6), (2, 6), (3, 6), (1, 7), (2, 7), (3, 7). В результате выполненных действий поддерево начиная с комментария № 6 становится дочерним элементом комментария № 3. Оператор CROSS JOIN создает все необходимые пути, даже если поддерево перемещается в дереве на более высокий или более низкий уровень.
Конструкция Таблица замыканий более проста, чем Вложенные множества. В обеих конструкциях существуют быстрые и несложные способы запроса предков и потомков, но Таблица замыканий в большей степени упрощает обслуживание иерархий. В обеих конструкциях более удобно запрашивать прямые дочерние или родительские узлы, чем в конструкциях Список соседства и Перечисление путей.
Тем не менее конструкцию Таблица замыканий можно улучшить, чтобы упростить выполнение запросов прямых родительских или дочерних узлов. Добавьте в конструкцию Таблица замыканий атрибут TreePaths .path_ lengtn. Значение path_length ссылки узла на самого себя равно нулю, значение pathlength прямого дочернего объекта этого узла равно 1, значение pathlength внучатого объекта узла равно 2 и так далее. Найти дочерние объекты комментария № 4 теперь просто:
Файл примера: Trees/soln/closure-table/child.sql
SELECT *
FROM TreePaths
WHERE ancestor = 4 AND path_length = 1; |