Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Drzewo kategorii i wyciąganie danych
Forum PHP.pl > Forum > PHP
zaksmok
Witam serdecznie. Stoję przed ciężkim problemem jakim jest drzewo kategorii.
Aktualnie korzystam z nested sets + parent_id

Jaki problem?

Mając następującą strukturę:

  1. - Kategoria 1
  2. - Sub 1.1
  3. - SubSub 1.1.1
  4. - SubSub 1.1.2
  5. - SubSubSub 1.1.2.1
  6. - SubSubSub 1.1.2.2
  7. - SubSubSub 1.1.2.3
  8. - Sub 1.2
  9. - SubSub 1.2.1
  10. - SubSub 1.2.2
  11. - Sub 1.3
  12. - Kategoria 2
  13. - Sub 2.1
  14. - SubSub 2.1.1
  15. - SubSub 2.1.2
  16. - Sub 2.2
  17. - Sub 2.3
  18. - Kategoria 3
  19. - Sub 3.1
  20. - Sub 3.2
  21. - Sub 3.3
  22. - Kategoria 4
  23. - Kategoria 5


będąc w kategorii Sub 1.2 powinienen widzieć:

  1. - Kategoria 1
  2. - Sub 1.1
  3. - Sub 1.2
  4. - SubSub 1.2.1
  5. - SubSub 1.2.2
  6. - Sub 1.3
  7. - Kategoria 2
  8. - Kategoria 3
  9. - Kategoria 4
  10. - Kategoria 5


a będąc w kategorii SubSubSub 1.1.2.2

  1. - Kategoria 1
  2. - Sub 1.1
  3. - SubSub 1.1.1
  4. - SubSub 1.1.2
  5. - SubSubSub 1.1.2.1
  6. - SubSubSub 1.1.2.2
  7. - SubSubSub 1.1.2.3
  8. - Sub 1.2
  9. - Sub 1.3
  10. - Kategoria 2
  11. - Kategoria 3
  12. - Kategoria 4
  13. - Kategoria 5


Próby skończyły się na następującym zapytaniu:
  1. SELECT * FROM categories WHERE parent_id IN(NULL, 1) OR lft BETWEEN 3 AND 7)


Przy takim zapytaniu muszę znać:
1. ID głównej gałęzi w nested sets (null lub id = 1, w zależności od struktury nested sets)
2. ID najwyższego rodzica otwartej kategorii (w moim zapytaniu id=1)
3. LFT i RGT najwyższego rodzica kategorii.

Dla struktury
  1. - Kategoria 1
  2. - Sub 1.1
  3. - SubSub 1.1.1
  4. - SubSubSub 1.1.1.1
  5. - SubSubSub 1.1.1.2
  6. - SubSubSub 1.1.1.3
  7. - SubSub 1.1.2
  8. - SubSubSub 1.1.2.1
  9. - SubSubSub 1.1.2.2
  10. - SubSubSub 1.1.2.3
  11. - Sub 1.2
  12. - SubSub 1.2.1
  13. - SubSub 1.2.2
  14. - Sub 1.3
  15. - Kategoria 2
  16. - Sub 2.1
  17. - SubSub 2.1.1
  18. - SubSub 2.1.2
  19. - Sub 2.2
  20. - Sub 2.3
  21. - Kategoria 3
  22. - Sub 3.1
  23. - Sub 3.2
  24. - Sub 3.3
  25. - Kategoria 4
  26. - Kategoria 5


bedąc w SubSubSub 1.1.2.1 powinienen otrzymać

  1. - Kategoria 1
  2. - Sub 1.1
  3. - SubSub 1.1.1
  4. - SubSub 1.1.2
  5. - SubSubSub 1.1.2.1
  6. - SubSubSub 1.1.2.2
  7. - SubSubSub 1.1.2.3
  8. - Kategoria 2
  9. - Kategoria 3
  10. - Kategoria 4
  11. - Kategoria 5



  1. SELECT * FROM categories WHERE parent_id IN (NULL, 1, 2) OR lft BETWEEN 7 AND 10


czyli muszę znać:
1. ID każdego rodzica
2. LFT i RGT najniższego rodzica

i to już mnie przerasta... Może znacie jakiś sprytny sposób na to?
wiiir
a jakie masz tabele?

jedna tabela z 4 kolumnami, gdzie kazda kolumna odpowiada za poziom?

Ja jestem zwolennikiem ze nie trzeba sie bac towrzenia i wizania ze soba tabel, wiec zrobil bym 4 table bo mamy 4 kategorie
daje mi to przejrzystosc tabel, zapytan i kodu, wkoncu dlatego bazy nazywaja sie relacyjnymi

  1. 1 petla
  2. warunek
  3. 2 petla
  4. wrunek
  5. 3 petla
  6. warunek
  7. 4 petla

moze ktos powiedziec boze ile zapytan po co itd.. ja wiem z doswiadczenia (oracle+ bardzo duza baza) ze takie zapytania beda wykonywac sie szybiej niz jedno wielkie ktore moze zapchac serwer jak jest zle napisane, w tym ukladnie mozna dodawac odpowiednie warunki kiedy jaki poziom sie wyswietla i dla kogo.. + wile innych plusow
zaksmok
gałęzie nie będą aż tak duże, maks 500 rekordów. Wszystko jest w jednej tabeli, struktura nested sets.
VegetaSSJ
Cytat(wiiir @ 25.02.2010, 10:16:49 ) *
Ja jestem zwolennikiem ze nie trzeba sie bac towrzenia i wizania ze soba tabel, wiec zrobil bym 4 table bo mamy 4 kategorie
daje mi to przejrzystosc tabel, zapytan i kodu, wkoncu dlatego bazy nazywaja sie relacyjnymi


OMG

Może to ci pomoże:

http://www.phpclasses.org/browse/package/1374.html
http://articles.sitepoint.com/article/hier...l-data-database
http://www.edutech.ch/contribution/nstrees/index.php

Poza tym na moje oko wszystkie kategorie powinny być opakowane jeszcze w nadrzędny element, np root.
ayeo
Witam!

@wiiir, to co proponujesz to jakiś absurd. Dobrych implementacji drzewek jak kilka. Można wybrać coś dla siebie w zależności od potrzeb i trudności. Jak w Twoim pomyśle będziesz realizował przeszukiwanie gałęzi lub przenoszenie? BTW relacją nie jest trzymanie danych tego samego rodzaju w 15 tabelkach.

Co do tematu wątku, mogę polecić jeszcze tzw Drzewka Depesza. Bez trudu znajdziesz w Google materiały. Jest to modyfikacja drzewek IP (taka bardziej zmiana optymalizacyjna). W drzewkach IP chodzi o to, że oprócz id rodzica trzymasz całą ścieżkę jeszcze (np 1.23.345.1224, parent to 1224, kategoria główna to 1). Drzewek LEFT-RIGHT nie mogłem nigdy zrozumieć. Tzn ich fenomenu.

Pozdrawiam!
Methestel
Problem ciekawy ale rozwiązanie jest dość proste.

Pola przykładowej tablicy 'tbl_tree'
- id
- parent_id
- n_left
- n_right
- level (liczba naturalna informująca o poziomie elementu w drzewie)

Kolumna "level" jest opcjonalna ale zawsze ją dodaję bo znacznie ułatwia wiele operacji na tablicy.



Zapytanie które wyciąga Ci id-ki wszystkich potomków elementu o id = :id już znasz i dla mojej przykładowej tabeli wygląda tak:

  1. SELECT *
  2. FROM tbl_tree
  3. WHERE (n_left > (SELECT n_left FROM tbl_tree WHERE id = :id)
  4. AND n_right < (SELECT n_right FROM tbl_tree WHERE id = :id))


Zapytanie które wyciągnie Ci id-ki wszystkich rodziców elementu o id = :id wygląda identycznie z dwiema drobnymi różnicami (znaki '>' i '<' zamieniły się miejscami):

  1. SELECT *
  2. FROM tbl_tree
  3. WHERE (n_left < (SELECT n_left FROM tbl_tree WHERE id = :id)
  4. AND n_right > (SELECT n_right FROM tbl_tree WHERE id = :id))


Żeby wyciągnąć n_left i n_right (u Ciebie LFT i RGT) najniższego rodzica przeszukujesz wynik poprzedniego zapytania w poszukiwaniu wiersza o najwyższej wartości 'level' lub robisz nowe zapytanie do bazy danych:

  1. SELECT n_left, n_right
  2. FROM tbl_tree
  3. WHERE (n_left < (SELECT n_left FROM tbl_tree WHERE id = :id)
  4. AND n_right > (SELECT n_right FROM tbl_tree WHERE id = :id))
  5. ORDER BY level DESC
  6. LIMIT 1
Crozin
Cytat
Drzewek LEFT-RIGHT nie mogłem nigdy zrozumieć. Tzn ich fenomenu.
Cały ich fenomen polega na tym, że część operacji wykonuje się na nich o wiele łatwiej - część oczywiście trudniej. Jest to po prostu kolejna implementacja tego samego mająca swoje wady i zalety.
cudny
A ja bym to rozwiązał rekurencyjnie:
http://forum.php.pl/index.php?showtopic=133135&hl=

pzdr
Cudny
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.