Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Drzewo z MySQL metodą trawersji.
Forum PHP.pl > Forum > Bazy danych > MySQL
sanneo
Witam wszystkich

Przeczytałem pewien artykuł http://www.sitepoint.com/article/hierarchical-data-database

Niestety nie opisuje jak poradzić sobie z typową sytuacją wielopoziomowego menu w serwisie.

Mam dane w takim formacie:

-message1
--message11
--message12
-message2
--message21
--message22
---message221
---message222
----message2221
----message2222
-----message22221
-----message22222
----message2223
---message223
-message3
--message31
---message311
---message312
---message313
--message32
-message4
--message41
--message42
-message5
--message51
--message52

Chciałbym wyświetlić tylko to:

-message1
-message2
--message21
--message22
---message221
---message222
----message2221
----message2222
-----message22221
-----message22222
----message2223
---message223
-message3
-message4
-message5

Dlatego, że wybrałem pozycję menu:

-----message22221

Macie jakiś pomysł jak to osiągnąć korzystając ze struktury bazy danych opisanej w artykule?

Z góry dziękuję.

Pozdrawiam.

Mariusz
dr_bonzo
Pobierz sobie top level
a do tego cale poddrzewo 2-ki a potem polacz.

ALE - pobrac kategorie pierwszego poziomu jest ciezko - dodanie parent_id do kazdego z elementow ci to ulatwi.
sanneo
Mam także parent_id, ale właśnie sztuka polega na tym, aby z tego nie skorzystać, chcę skorzystać z trawersji.

Mechanizm musi być uniwersalny dla różnego kształtu drzewa.

Pozdrawiam.
dr_bonzo
Cytat
Mam także parent_id, ale właśnie sztuka polega na tym, aby z tego nie skorzystać, chcę skorzystać z trawersji.


Ło matko, to se zrob bez uzywania parent_id.

Sztuka polega na tym zeby ZROBIC, zeby dzialalo i zeby bylo szybkie, a nie "nie chce tego uzyc bo nie, bo tak nie napisali w ksiazce".
Troche pragmatyzmu a nie idealizmu.
Nie wszystkie implementacje drzewka sa idealne - w zasadzie kazde kuleje w innej dziedzinie. CHodzi o to zeby dobrac impl. do twoich potrzeb. A gdy zadna ci nie pasuje to trzeba wymyslic nowa.

Myslalem troche nad tym problemem i raczej(exclamation.gif) nie da sie tego (najwyższego poziomu kategorii) szybko pobrac bez parent id.

Cytat
Mechanizm musi być uniwersalny dla różnego kształtu drzewa.

Nie widze problemu. Drzewo nie ma ksztaltu. Ma tylko korzen (moze byc nieobecny, ale logicznie istnieje (wszystkie twoje kategorie glowne maja wspolnego rodzica - NULL)), a kazdy element drzewa ma swojego rodzica.
Zyx
http://artykuly.zyxist.com/czytaj.php/drzewa_w_php_i_mysql <- tu masz artykuł umożliwiający szybkie pobranie danego wycinka drzewa.

Możliwości:
- Szybkie pobieranie fragmentu drzewa od danego węzła do wszystkich jego liści.
- Szybkie pobieranie ścieżki do korzenia.
- Szybkie zliczanie węzłów podrzędnych.

Wady:
- Podczas pobierania fragmentu drzewa nie da się na poziomie bazy zignorować gałęzi drzewa od zadanego węzła w dół.
- Dość skomplikowana implementacja, zwłaszcza przy bardziej zaawansowanych operacjach.
- Nie da się pobrać pojedynczego poziomu drzewa.
- Modyfikacja drzewa wymaga co najmniej kilku zapytań SQL. Stanowczo odradzam implementowanie tego na czymś innym niż InnoDB i transakcjach, bo inaczej kłopoty mamy murowane.

Stosowałem ten algorytm w połączeniu z polem parent_id, którego używałem do wyświetlania pojedynczego poziomu drzewa w administracji i "płaskich" operacji na danym poziomie. Poszukaj dobrze na forum, gdyż był tu swego czasu temat z podaną całą masą różnych implementacji.
sanneo
dr_bonzo, nie pomogłeś mi w ogóle, ale za to sie wzburzyłeś...

Jeśli czytałeś artykuł do którego link podałem to możesz wywnioskować, że nie chodzi o to, że ktoś napisał coś w książce że tak ma być lub nie ma być, chodzi o to, aby drzewo działało optymalnie i możliwie najmniej obciążało bazę danych i procesy PHP.

Połączyłem sobie parent_id z ta metodą z linka, który podałem i osiągnąłem taki efekt jak potrzeba, ale z wydajnością gorzej, bo na każdą podgałąź wychodzi dodatkowe zapytanie SQL.

Czyli nie satysfakcjonuje mnie takie rozwiązanie.

Ciesze się, że to, że chwile pomyślałeś nad tym, niestety bez efektu, tak jak i ja.

Jeśli znajdziesz rozwiązanie problemu, który opisałem w sposób optymalny jak napisałem, to proszę daj znać.

Na pewno takie rozwiązanie przyda się niejednej osobie.

@Zyx, link który podałeś bazuje na rozwiązaniu do którego link podałem w pierwszym poście.

Pozdrawiam.

Mariusz (sanneo)
alegorn
stary temat, ale w sumie wart by dac odpowiedz wink.gif
o ile dobrze rozumiem - chodzi by wybrac jendna galaz z drzewa?


PARENT_ID - zmienna zawierajaca id, od ktorego pobieramy galaz
masz tutaj takze zliczanie elementow w galezi drzewa.


  1. SELECT
  2. node.name,
  3. (COUNT(parent.id) - (sub_tree.lvl + 1)) AS lvl,
  4. node.id,
  5. ROUND((((`node`.`rgt` - `node`.`lft`) - 1) / 2),0) AS `child_count`
  6.  
  7. FROM tree AS node,
  8. tree AS parent,
  9. tree AS sub_parent,
  10. (
  11. SELECT node.id, (COUNT(parent.id) - 1) AS lvl, parent.id AS parentId
  12. FROM tree AS node,
  13. tree AS parent
  14. WHERE node.lft BETWEEN parent.lft AND parent.rgt
  15. AND node.id = PARENT_ID
  16. GROUP BY node.id
  17. ORDER BY node.lft
  18. )AS sub_tree
  19. WHERE node.lft BETWEEN parent.lft AND parent.rgt
  20. AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
  21. AND sub_parent.id = sub_tree.id
  22. GROUP BY node.id
  23. ORDER BY node.lft;
  24.  
  25.  




z doswiadczenia wiem, ze najlepej to opakowac do procedury..
w swoim czasie napisalem chyba wszystkie funkcje (w sql wink.gif ) dla obslugi drzewka (wstawiania, kasowanie, przenoszenie elementow i galezi, pobranie sciezki etc.) fajna zabawa, w zasadzie do dzis z tego korzystam,

btw to chyba najwydajniejszy sposob na drzewko, przynajmniej jesli mamy dynamiczna ilosc zaglebien.

j.


edit: oczywiscie to zapytanie daje nam drzewko w upozadkowanej strukturze.
jesli bysmy mieli tylko wybrac wszystkie elementy z danej galezi - no to wystarczy beetwen lft and rgt
Pilsener
A ja polecam drzewa metodą IP. Poza parent_id dodajemy dwa pola pomocniczne: ip oraz depth. Ip zawiera zapis miejsca w strukturze poprzez przechowanie ID wszystkich nadrzędnych kategorii, np: 1.34.45.345 a depth to oczywiście poziom zagłębienia. Teraz jak chcemy pobrać gałąź np. 34 ale bez podkategorii to żaden problem użyć LIKE na polu IP oraz wykorzystać depth.

Zalety tej metody:
- przejrzysta, nawet laik zrozumie strukturę danych
- można szybko i prosto wykonywać operacje (nie sprawia problemów nawet przy przenoszeniu gałęzi)
- pobierając dowolny element cały czas znamy jego miejsce w drzewie, dzięki czemu łatwo np. wygenerować breadcrumb


Wady:
- trochę dodatkowej pracy przy tworzeniu pól IP oraz depth.

Przykładowo zliczenie elementów gałęzi 34 wyglądałoby tak:
  1. SELECT count(*) FROM tree WHERE ip LIKE "%34%"
- podejrzewam, że to trochę wygodniejsze i szybsze niż przykład powyżej wink.gif

A pobranie wszystkich kategorii do 3 poziomu włącznie:
  1. SELECT * FROM tree WHERE depth < 4


Alternatywne rozwiązania moim zdaniem nie sprawdzają się równie dobrze, choć może są "bardziej naukowe".
alegorn
taak naporawde sa trzy metody, ktore sie stosuje (czytalem gdzies jeszcze o 4)
kazde z nich ma swoje wady i zalety, sztuka polega na tym, by odpowiednia metode zaangazowac do problemu ktory mamy rozwiazac.
co oczywiscie wymaga rozpoznania danego problemu wink.gif



co do porównywania metod - ja tym jednym zapytaniem - wyciagam cale drzewko, ulozone w strukture i zawierajace dodatkowe info (lvl, child count )
w pozostalych metodach - nie zrobisz tego jednym zapytaniem.

ale to nie znaczy ze pozostałe metody nie maja zalet. trzeba jedynie wiedziec co potrzebujesz, i jak tego mozna uzyc.
czesto gesto tworzysz nawet hybrydy tych rozwiazan, co powoduje co prawda wieksze komplikacje w utrzymaniu struktury drzewka, ale dają zysk w odczycie.

j.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.