Рекурсивно получить этот результат сложно (хотя и возможно). Однако, как правило, он не очень эффективен, и есть намного лучший способ решить эту проблему.
По сути, вы дополняете таблицу дополнительным столбцом, который прослеживает дерево до вершины - я назову его «Upchain». Это просто длинная строка, которая выглядит примерно так:
name | id | parent_id | upchain
root1 | 1 | NULL | 1:
root2 | 2 | NULL | 2:
root1sub1 | 3 | 1 | 1:3:
root1sub2 | 4 | 1 | 1:4:
root2sub1 | 5 | 2 | 2:5:
root2sub2 | 6 | 2 | 2:6:
root1sub1sub1 | 7 | 3 | 1:3:7:
Очень легко обновлять это поле, используя триггер на столе. (Извиняюсь за терминологию, но я всегда делал это с SQL Server). Каждый раз, когда вы добавляете или удаляете запись, или обновляете поле parent_id, вам просто нужно обновить поле upchain в этой части дерева. Это тривиальная работа, потому что вы просто берете цепочку родительской записи и добавляете идентификатор текущей записи. Все дочерние записи легко идентифицируются с помощью LIKE для проверки записей со стартовой строкой в цепочке.
То, что вы делаете эффективно, - это обмен небольшого количества дополнительных операций записи на большое сохранение, когда вы приходите, чтобы прочитать данные.
Если вы хотите выбрать полную ветку в дереве, это тривиально. Предположим, вы хотите ветвь под узлом 1. Узел 1 имеет цепочку «1:», поэтому вы знаете, что любой узел в ветке дерева под этим узлом должен иметь цепочку, начинающуюся с «1: ...». Итак, вы просто делаете это:
SELECT *
FROM table
WHERE upchain LIKE '1:%'
Это чрезвычайно быстро (конечно, индексируйте поле восходящей цепи). В качестве бонуса он также делает чрезвычайно простыми многие действия, такие как поиск частичных деревьев, уровня внутри дерева и т. Д.
Я использовал это в приложениях, которые отслеживают большие иерархии отчетов сотрудников, но вы можете использовать его практически для любой древовидной структуры (разбивка деталей и т. Д.)
Примечания (для всех, кому интересно):
- Я не дал пошагового кода SQL, но как только вы поймете принцип, его довольно просто реализовать. Я не большой программист, поэтому я говорю по своему опыту.
- Если у вас уже есть данные в таблице, вам нужно выполнить однократное обновление, чтобы изначально синхронизировать цепочки операций. Опять же, это не сложно, так как код очень похож на код UPDATE в триггерах.
- Этот метод также является хорошим способом определения круговых ссылок, которые в противном случае сложно обнаружить.