W poprzednich artykułach tej serii pokazałam jak wygląda konstrukcja drzewa typu nested set a także jak wczytać zawartość drzewa tego typu. W tym odcinku pokażę, że wystarczą niewielkie modyfikacje omówionych wcześniej zapytań, by bez trudu odczytać dowolnie wybraną gałąź naszej struktury.
Dla przypomnienia
Na początek przypomnę tabelę zawierająca strukturę drzewa, którą wykorzystywałam w poprzednich artykułach oraz wygląd drzewa jaki można uzyskać wykonując jedno z dwóch pokazanych poniżej zapytań.
SELECT concat( repeat('-', COUNT(parent.id) - 1),child.title) AS title, child.id FROM tree AS child, tree AS parent WHERE child.lft BETWEEN parent.lft AND parent.rgt GROUP BY child.id ORDER BY child.lft
SELECT concat( repeat('-', (SELECT count(parent.id)-1 FROM tree AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt) ),node.title) AS title, node.id FROM tree AS node ORDER BY node.lft
Wczytanie gałęzi
Załóżmy teraz, że chcemy wczytać tylko gałąź zaczynającą się od rekordu o id=2 (title=Windows). Nic prostszego wystarczy zapytać o rekordy, których wartości parametrów ‘lft’ i ‘rgt’ mieszczą się pomiędzy 2 a 13, takie bowiem wartości mają te parametry dla wybranego przez nas rekordu. Tak więc wykonanie jednego z poniższych zapytań da zamierzony efekt, co widać na załączonej ilustracji.
SELECT concat( repeat('-', COUNT(parent.id) - 1),child.title) AS title, child.id FROM tree AS child, tree AS parent WHERE child.lft BETWEEN parent.lft AND parent.rgt AND child.lft BETWEEN 2 AND 13 GROUP BY child.id ORDER BY child.lft
SELECT concat( repeat('-', (SELECT count(parent.id)-1 FROM tree AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt) ),node.title) AS title, node.id FROM tree AS node WHERE node.lft BETWEEN 2 AND 13 ORDER BY node.lft
Wykluczenie gałęzi
W podobny sposób można wykluczyć jakąś gałąź odczytując strukturę drzewa. Zabieg ten jest przydatny podczas przenoszenia gałęzi. W strukturze drzewa zakodowana jest pewna hierarchia. Przenosząc gałąź należy uniemożliwić podanie jako miejsca docelowego, elementu, który do tej gałęzi należy. Także i w tym wypadku modyfikacja obu alternatywnych zapytań jest niewielka. Załóżmy, że chcemy wykluczyć tę samą gałąź, którą poprzednio wczytywaliśmy. Zapytania przybiorą następującą formę:
SELECT concat( repeat('-', COUNT(parent.id) - 1),child.title) AS title, child.id FROM tree AS child, tree AS parent WHERE child.lft BETWEEN parent.lft AND parent.rgt AND (child.lft < 2 OR child.rgt > 13) GROUP BY child.id ORDER BY child.lft
SELECT concat( repeat('-', (SELECT count(parent.id)-1 FROM tree AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt) ),node.title) AS title, node.id FROM tree AS node WHERE node.lft < 2 OR node.rgt > 13 ORDER BY node.lft
Podsumowanie
Warto zauważyć, że opisane powyżej operacje, w przypadku drzewa zrealizowanego tak jak to pokazałam w pierwszym artykule na temat struktur drzewiastych byłyby niemal nie do wykonania na poziomie bazy danych. Aby je przeprowadzić trzeba by wczytywać cała tabelę i dopiero za pomocą skryptu analizować. Dlatego uważam, że zaprezentowane tu zapytania, mimo iż mogą sprawiać trudności początkującym programistom, są wygodne i pozwalają operować danymi w sposób elegancki.
Zbiory zagnieżdżone są w miarę przyjazne na etapie wybierania danych. Czekam jak podejdziesz do tematu modyfikacji struktury drzewa, a zwłaszcza przenoszenia całych gałęzi.
17-tego maja ukarze się kolejny artykuł, tym razem o dodawaniu rekordów do struktury. W następnej kolejności pojawi się tekst właśnie o przenoszeniu gałęzi, tak więc trzymaj rękę na pulsie :)
A ja właśnie dlatego zainteresowałam się taką implementacją drzewa, bo wychodzę z założenia, że tego typu struktury jednak dużo częściej się odczytuje niż modyfikuje. Warto więc podjąć wysiłek związany z implementacją mechanizmów pozwalających na modyfikację, po to, żeby mieć ułatwioną sprawę przy odczycie.