Имайки предвид тези ограничения, няма начин. В такъв случай или ще извлечете всички дървото и изградете „хълм“ клиентска страна или изпълнете рекурсивни заявки, каквото би било най-ефективно в конкретния случай.
С допълнителното ограничение за наличието на фиксиран брой нива на йерархия , можете да направите това с множество JOIN.
В общия случай има няколко структурни модификации, които позволяват преодоляването на тези ограничения. На практика облекчавате ограничението "ТОВА е структурата на моята таблица", което позволява добавяне на допълнителни полета.
Например, можете да допълните структурата на възела с left_id
стойност и се уверете, че всички идентификатори на възли са в последователност, когато посетите дървото в дълбочина първо:
1 --- 2 -+- 3 -+- 4
| |
| +- 5
+- 6 --- 7
В този случай възел 3 ще съхрани стойността "5", възел 6 ще съхрани стойността "7", а възел 2 също ще съхрани стойността "7". Всеки възел съхранява в LeftID максимума между левите си идентификатори на децата и собствения си идентификатор .
Така възлите без деца имат LeftID, равен на техните идентификатори. Възел 1 ще има LeftID 7, тъй като това е LeftID от 2, което го получи от 6.
В тази ситуация отброяване възли е лесно, ако няма дупки в последователността; всички потомци на възел са онези възли, чийто идентификатор е между идентификатора на началния възел и неговия ляв идентификатор; и листата се идентифицират като имат LeftID, равен на ID.
Така че "всички листа, слизащи от идентификатор на възел 17" ще бъдат
SELECT child.*FROM table AS parentJOIN таблица AS childON (child.id> parent.id AND child.id <=parent.leftid ) /* Descendant /WHERE child.id =child.leftid / Лист /AND parent.id =17; / Родителят е на 17
Тази структура е неудобна за поддържане, ако искате да можете да правите подрязване и разклоняване, тъй като трябва да преномерирате всички възли между точката на подрязване до точката на разклоняване, както и преместените възли.
Друга възможност, ако се интересувате само от броене, е да запазите детски брояч. Това може да се поддържа, като го актуализирате итеративно, като изберете всички листа и зададете брояча им на 0 (вие идентифицирате листа чрез LEFT JOIN); след това всички онези родители с броячи NULL, които имат деца с броячи без NULL, актуализирайки броячите си до SUM()
детски броячи плюс COUNT()
на самите деца; и продължава, докато броят на актуализираните редове стане нула, тъй като всички възли имат броячи без NULL. След подрязване и разклоняване просто задавате всички броячи на NULL и повтаряте.
Този последен подход струва отразяващо присъединяване за всяко ниво на йерархия.