Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PHP/MySQL
Forum PHP.pl > Forum > PHP
ksenonlogin
Witam

Problem wygląda tak:

mam dwie tabele: kategorie oraz przedmiot, wiadomo że w przedmiocie(aukcji) zawierają się klucze o wartości "id_kategoria", jednak tabela przedstawia drzewo kategorii więc produkt jest przypięty do końcówki (kategoria "laptop" zawiera "acer" oaz "samsung" więc Acer inspiron X3 będzie zawierał klucz z "acer" anie z "laptop"), i właśnie tu zaczyna się problem: jak kliknę na link acer to wyświetlę spokojnie acery ale jak kliknę "laptop" to jak mam wyświetlić produkty podkategorii zachowując sortowanie ogólne (np. produkty po czasie rejestracji) - wspomnę iż zagłębienie kategorii jest nieograniczone.

Niżej przedstawiam tabelę oraz funkcję rysującą drzewo kategorii.

Tabela aukcji:
  1. CREATE TABLE IF NOT EXISTS `przedmiot` (
  2. `id_przedmiot` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `klucz_user_przedmiot` mediumint(8) UNSIGNED DEFAULT NULL,
  4. `klucz_kategoria_przedmiot` mediumint(7) UNSIGNED NOT NULL,
  5. `zdjecie_przedmiot` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
  6. `tytul_przedmiot` varchar(70) COLLATE utf8_unicode_ci NOT NULL,
  7. `krotki_opis_przedmiot` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
  8. `klucz_opis_przedmiot_przedmiot` mediumint(8) UNSIGNED NOT NULL,
  9. `cena_przedmiot` double(10,2) UNSIGNED NOT NULL,
  10. `stan_magazynowy_przedmiot` mediumint(5) UNSIGNED NOT NULL,
  11. `czas_trwania_przedmiot` tinyint(2) UNSIGNED DEFAULT NULL,
  12. `klucz_opcje_dostawy_koszt_przedmiot` mediumint(8) UNSIGNED NOT NULL,
  13. `wysylka_w_ciagu_przedmiot` tinyint(1) UNSIGNED DEFAULT NULL,
  14. `faktura_vat_przedmiot` tinyint(1) UNSIGNED DEFAULT NULL,
  15. `dotadkowe_informacje_przedmiot` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL,
  16. `p_stronaglowna_przedmiot` tinyint(1) UNSIGNED NOT NULL,
  17. `p_stronakategorii_przedmiot` tinyint(1) UNSIGNED NOT NULL,
  18. `p_wyroznienieproduktu_przedmiot` tinyint(1) UNSIGNED NOT NULL,
  19. `p_podswietlenie_przedmiot` tinyint(1) UNSIGNED NOT NULL,
  20. `p_produktwpromocja_przedmiot` double(10,2) UNSIGNED NOT NULL,
  21. `status_przedmiot` tinyint(2) DEFAULT NULL,
  22. `data_rejestracji_przedmiot` datetime NOT NULL,
  23. `data_zakonczenia_przedmiot` datetime DEFAULT NULL,
  24. PRIMARY KEY (`id_przedmiot`),
  25. KEY `krotki_opis_przedmiot_2` (`krotki_opis_przedmiot`),
  26. KEY `tytul_przedmiot_3` (`tytul_przedmiot`),
  27. KEY `krotki_opis_przedmiot_3` (`krotki_opis_przedmiot`),
  28. FULLTEXT KEY `tytul_przedmiot` (`tytul_przedmiot`),
  29. FULLTEXT KEY `krotki_opis_przedmiot` (`krotki_opis_przedmiot`),
  30. FULLTEXT KEY `tytul_przedmiot_2` (`tytul_przedmiot`),
  31. FULLTEXT KEY `tytul_przedmiot_4` (`tytul_przedmiot`),
  32. FULLTEXT KEY `krotki_opis_przedmiot_4` (`krotki_opis_przedmiot`)
  33. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10000586 ;



Tabela kategorie:
  1. CREATE TABLE IF NOT EXISTS `kategoria` (
  2. `id_kategoria` mediumint(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `rodzic_kategoria` mediumint(7) UNSIGNED NOT NULL,
  4. `nazwa_kategoria` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  5. `tytul_kategoria` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
  6. `meta_description` varchar(700) COLLATE utf8_unicode_ci DEFAULT NULL,
  7. `meta_keywords` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL,
  8. `przyjazny_url_kategoria` varchar(400) COLLATE utf8_unicode_ci DEFAULT NULL,
  9. `status_kategoria` smallint(5) UNSIGNED NOT NULL,
  10. PRIMARY KEY (`id_kategoria`)
  11. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10000228 ;




Funkcja rysująca drzewo:

  1. function view_category_ul_li_tree_root($rodzic_kategoria, $level) { $result = mysql_query("SELECT a.id_kategoria, a.nazwa_kategoria, a.przyjazny_url_kategoria, Deriv1.Count FROM `kategoria` a LEFT OUTER JOIN (SELECT rodzic_kategoria, COUNT(*) AS Count FROM `kategoria` GROUP BY rodzic_kategoria) Deriv1 ON a.id_kategoria = Deriv1.rodzic_kategoria WHERE a.rodzic_kategoria=" . $rodzic_kategoria);
  2.  
  3. while ($row = mysql_fetch_assoc($result)) {
  4.  
  5. if ($row['Count'] > 0) {
  6.  
  7. $ar .= '<li id="id' . $row['id_kategoria'] . '" class="folder"><span><a href="#" onClick="loadPage1(\'./index.php?view=category&action=editcategory&decision=show&type_of_loading=ajax&delete=no&id_category=' . $row['id_kategoria'] . '\');">' . $row['nazwa_kategoria'] . '</a></span>
  8. <ul>'.view_category_ul_li_tree_root($row['id_kategoria'], $level + 1).'</ul></li>';
  9.  
  10. } elseif ($row['Count'] == 0) {
  11. $ar .= '<li class="noLink" id="id' . $row['id_kategoria'] . '"><span><a href="#" onClick="loadPage1(\'./index.php?view=category&action=editcategory&decision=show&type_of_loading=ajax&delete=yes&id_category=' . $row['id_kategoria'] . '\');">' . $row['nazwa_kategoria'] . '</a></span></li>';
  12. }
  13. }
  14. return $ar;
  15. }
sebastian.rozmus
Możesz zrobić to zagnieżdzając zapytania MySQL albo dodając pole varchar zawierające numery id wszystkich kategorii od aktualnej do samej góry. Np.:

Acer; ID: 1; ścieżka: "1,"
Inspiron X3; ID: 2; ścieżka: "1,2,"

Ścieżkię generujesz przy dodawaniu przedmiotu. A zapytanie coś w tym stylu:

  1. SELECT przedmiot p LEFT JOIN kategoria k ON k.id_kategoria = p.klucz_kategoria_przedmiot WHERE k.sciezka LIKE '{$sciezka_aktualnej_kategorii}%'


Wydaje mi się, że rozwiązanie jest dobre, choć niezbyt eleganckie. Jeśli nie jest dobre, to poproszę o krytykę smile.gif
ksenonlogin
Mi za bardzo to nie pasuje, jeżeli kategoria będzie częścią podkategorii to trzeba się liczyć z tym że przy dużej liczbie kategorii i zagnieżdżeń będzie taki moment że połączona ścieżka stworzy jakąś kategorię (chyba że tak jak napisałeś jest to pole varchar czymś tam rozdzielone) jednak rzeczywiście jest to nieeleganckie wink.gif

wolałbym coś praktycznego, ponieważ kończę pisać dość pokaźny sklep jednak zatrzymałem się własnie na tej niby banalnej rzeczy (po prostu nie mogę sobie tego działania w głowie ułożyć)

Czekam na więcej pomysłów jak by było można to wykombinować wink.gif
mortus
@sebastian.rozmus: Oczywiście rozwiązanie jest jak najbardziej dobre i ma nawet swoją nazwę - drzewo IP.

@ksenonlogin: Niestety przy takiej budowie systemu kategorii i podkategorii, która opiera się jedynie na id i parentId ciężko będzie znaleźć wydajne rozwiązanie. Musisz bowiem napisać sobie funkcję rekurencyjną, która wyszuka wszystkie podkategorie w danej kategorii i w jej podkategoriach, i tak w kółko. Znalezione id podkategorii wrzucasz do zapytania:
SELECT ... FROM `przedmiot` WHERE `klucz_kategoria_przedmiot` IN (tutaj znalezione identyfikatory kategorii)
Niestety funkcja rekurencyjna wykonywać będzie masę zapytań SQL, co zdecydowanie wpłynie na spadek wydajności aplikacji i wyszukiwanie podkategorii danej kategorii trochę czasu zajmie (oczywiście to zależy od ilości kategorii i podkategorii). Zdecydowanie lepszym rozwiązaniem będą tutaj zaproponowane wyżej drzewa IP.

Oczywiście są jeszcze inne sposoby na zaimplementowanie drzewa kategorii, a wszystkie je łączy wspólny element - zbiory zagłębione (nested sets).
ksenonlogin
Szukałem szukałem i nic nie znalazłem więc zrobiłem według waszych zaleceń i powiem szczerze że jest ok - nie daje znacznego obciążenia wink.gif

Dzięki wink.gif
alegorn
@mortus nested sets jest trudnym sposobem implementacji drzewka (trochę nieintuicyjne na początek)
jednak jak sie człowiek zagłębi w temat - to widać same zalety :]

tutaj topic odpisałem jak można łatwo wybrać cala gałąź drzewka.

drzewa z rodzicem - są ok, ale tylko wtedy gdy znamy ilość zagłębień, no i tych zagłębień nie jest zbyt wiele.
inaczej - wychodzi makabra, ilość zapytań jaka trzeba wysłać by pobrać pełne drzewo jest koszmarna...
j.
ksenonlogin
Przekonaliście mnie, powiem szczerze że nawet większy porządek i w razie problemu z bazą łatwiej znaleźć problem przy zagubionych elementach wink.gif

@alegorn: dzięki za dodatkowy temat przydał się ;:
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.