Hmmm... znam troszkę przekombinowaną wg niektórych metodę ale póki co... idealną na moje potrzeby. KAŻDA inna metoda jaką próbowałem miała swoje wady. Ta którą używam nazywana jest po prostu Nested Tree. Zasada jej działania jest opisana tutaj
http://dev.mysql.com/tech-resources/articl...hical-data.htmlpod nagłówkiem The Nested Set Model. Żeby niektórzy szybciej załapali to w skrócie powiem o co chodzi. Każdy element tablicy opisany jest za pomocą 2 właściwości. LEWA i PRAWA :-D. Czym jest lewa i prawa sami określcie. Najczęściej stosuje się trzecią wskazującą na poziom zagnieżdżenia. Rzecz przydatna ale nie jest niezbędna.
Jak to wygląda w praktyce ?
Elemenyt 1 --- LEWA 1 | PRAWA 2 | LVL 1
Wartość lewa to po prostu numeracja. Wartość prawa jest obliczana wg prostego wzoru:
PRAWA = LEWA + (ILOŚĆ_DZIECI * 2) + 1;
W tym wypadku jak chcemy dodać element 2, robimy to tak
Element1 --- LEWA 1 | PRAWA 2 | LVL 1
Element1 --- LEWA 3 | PRAWA 4 | LVL 1
Debilnie proste prawda ? Skoro 1 i 2 są zajęte to kolejny element dostaje cyfrę 3 na lewo i na prawo obliczamy wg wzorca: PRAWA = 3 ( 0*2 ) + 1; czyli 4.
I tak z każdym kolejnym elementem.
Teraz pytanie... co z dziećmi ? A no najpierw może pokaże jak wygląda drzewo z dzieckiem a potem wyjaśnię:
Element1 --- LEWA 1 | PRAWA 4 | LVL 1
Element3 --- LEWA 2 | PRAWA 3 | LVL 2
Element2 --- LEWA 5 | PRAWA 6 | LVL 1
Dodajmy kolejny element
Element1 --- LEWA 1 | PRAWA 6 | LVL 1
Element3 --- LEWA 2 | PRAWA 3 | LVL 2
Element4 --- LEWA 4 | PRAWA 5 | LVL 2
Element2 --- LEWA 7 | PRAWA 8 | LVL 1
Teraz jeszcze dla jasności do elementu 3 coś dodamy:
Element1 --- LEWA 1 | PRAWA 8 | LVL 1
Element3 --- LEWA 2 | PRAWA 5 | LVL 2
Element5 --- LEWA 3 | PRAWA 4 | LVL 3
Element4 --- LEWA 6 | PRAWA 7 | LVL 2
Element2 --- LEWA 9 | PRAWA 10 | LVL 1
Zobaczcie że zasada jest WSZĘDZIE taka sama. Wzór dla element1 to PRAWA = 1 + (3 * 2) + 1 czyli PRAWA = 1 + 6 + 1 czyli 8.
Kiedy dokładamy element WEWNĄTRZ drzewa to WSZYSTKIE elementy które są wyżej mają wartość PRAWĄ o 2 większą. Z kolei elementy niżej mają LEWĄ I PRAWĄ o 2 WIĘKSZĄ.
A zasada jest prosta. ILOŚĆ DOKŁADANYCH ELEMENTÓW * 2 więc jak na raz wsadzicie 10 elementów to wartość prawa tych wyżej wzrasta o 20 a lewa i prawa niżej o tyle samo.
_______________________________________________
Teraz pewnie chcecie mnie skrytykować, będziecie twierdzić że metoda jest dzika, skomplikowana i w ogóle zła. Cóż... raczej nie macie racji. Wystarczy troszkę pomyśleć nad zaletami i wadami tej metody.
ZALETY:
1. W tabeli BD, wszystkie rekordy są przechowywane za porządkiem i nie musimy z niczym kombinować. Po prostu do tabeli mamy 2 lub 3 pola więcej.
2. Sortując elementy od LEWEJ wartości dostajemy drzewo w odpowiedniej kolejności. Jak nałożycie indeksy na LEWA / PRAWA to BD tego nawet nie poczuje. A i bez tego nie ma problemu bo mamy tu do czynienia z wartościami numerycznymi.
3. Niemal WSZYSTKIE operacje wybierania robimy na 2 zapytaniach do bazy.
4. Metoda nie ma ograniczeń co do wielkości. Problem napotkacie jak się wam big int skończy

5. Metoda jest bardzo szybka.
6. Mamy PEŁNĄ kontrolę nad kolejnością elementów w drzewie (z czym również niektóre metody sobie nie radzą do końca).
WADY:
1. No niestety musicie zastosować ten tragicznie trudny wzór jaki Wam podałem i zasadę zwiększania wartości jak dodamy coś do bazy.
2. Dodawanie / usuwanie i przenoszenie elementów w bazie wymaga 3-5 zapytań.
3. Trzeba pomyśleć żeby metodę zaimplementować ?
PRZYKŁADY MOŻLIWOŚCI:
( wybieramy wartość LEWĄ I PRAWĄ elementu X który nas interesuje)
1. Zakładamy że potrzeba nam całe drzewko w odpowiedniej kolejności
- select z sortowaniem wg wartości lewej
2. Potrzeba nam wybraną gałąź drzewa (element X)
- Teraz jak chcemy np wszystko co znajduje się w tym elemencie to pobieramy wartość LEWA WIĘKSZĄ JAK LEWA X oraz LEWA MNIEJSZĄ JAK PRAWA X. Gotowe.
3. Potrzeba nam wszystko POZA wybraną gałęzią drzewa (poza elementem X)
- to samo tylko wartość LEWA MNIEJSZA od LEWA X i LEWA WIĘKSZA od PRAWA X.
4. Potrzeba nam wszystkich RODZICÓW elementu X, tu parę metod ma problem (np wymaga wielokrotnych zapytań do bazy). Tutaj:
- wybieramy wartość PRAWA WIĘKSZA OD PRAWA X i LEWA MNIEJSZA OD LEWA X.
5. Potrzeba nam elementy BEZ DZIECI
- PRAWA - LEWA - 1 ma wynosić 0
6. Potrzeba nam elementy z dziećmi
- PRAWA - LEWA - 1 > 0
7. Potrzeba nam elementy z 5 dziećmi
- (PRAWA - LEWA - 1) / 2 = 5
itp...
itd...
etc...
Możliwości jest na prawdę dużo a mają wybrany element (jego wartość lewą i prawą) możemy dowiedzieć się o nim wszystko. Na większość operacji potrzeba 1-2 zapytań (przy czym jedno zapytanie to właśnie odnalezienie lewej i prawej wartości elementu którego np dzieci możemy poszukać.
LVL przydaje się w paru przypadkach więc warto go mieć w bazie. Np wypisując drzewo zagnieżdżam je właśnie wg lvl. Sortując wg lewej wartości drzewo mam pewność że kolejność jest odpowiednia. Jeżeli LVL się zwiększył o 1, otwieram UL i zapamiętuje nowy LVL, jak się zmniejszył to zamykam UL i zapamiętuje nowy lvl. Proste. Jak nie chcemy mieć zagnieżdżonych list to lvl może nam powiedzieć jak duże wcięcie zrobić (prosto łatwo i skutecznie).
Problemem są operacje manipulowania drzewem ale przecież na ogół takowe się często nie zmienia. Chodzi o to musimy zwiększyć wartość prawą u elementów go poprzedzających, lewą i prawą następujących a potem wstawić element.
Przy usuwaniu trzeba zrobić to samo ale odwrotnie. Czyli usunąć element, zmniejszyć wartość prawą u rodziców i lewą oraz prawą wśród dzieci.
Przy przenoszeniu elementów w drzewie właściwie robimy jedno i drugie. Najpierw traktujemy element jak by był usunięty a potem "udajemy że go wstawiamy".
Przenoszenie może Wam się przy czymś takim wymagającym obliczeń wydawać dzikie ale nie jest. Lewa i prawa wartość jest stała bo jest obliczana ze wzoru. Zawsze jest to ilość elementów wewnątrz * 2 + 1 + lewa. Więc co wystarczy zrobić ? Jak przenosimy element to musimy znaleźć lewą i prawą wartość elementu gdzie jest on przenoszony a następnie obliczyć różnicę :-) I tak korygujemy wartości lewe, prawe i lvl bez skomplikowanych obliczeń.
Pozdrawiam i będę zdziwiony jak ktoś ten post doczyta do tego momentu. Wybaczcie że tego dokładniej nie opisałem ale nie chciało mi się robić obrazków i wykresów. Jak chcecie mieć jakieś wizualne przedstawienie metody to wejdźcie na link do dev.mysql który podałem. Opisuje on metodę i na okręgach pokazuje dokładnie o co chodzi.