Wpis z mikrobloga

Potrzebuje wydajnego sposobu na wyświetlanie produktów z wielu kategorii.
Załóżmy, że mam coś takiego

Kategoria 1
- Subkategoria
- Subkategoria
- - Sub subkategoria
- - Sub subkategoria
- - - Sub sub subkategoria
- Subkategoria
Kategoria 2
- Subkategoria
...

I teraz klikając w sub sub subkategoria mam zapytanie WHERE category = ID ale klikając w Sub subkategoria muszę mieć już WHERE category IN (id1, id2) a z kolei klikając w Kategoria 1 tych id w IN będzie już dużo (tym bardziej, że kategorie są tak na prawdę miastami, regionami, województwami i krajami)...

W jaki sposób rozwiązać to inaczej, lepiej, uniwersalnie, ..., żeby nie mieć WHERE category IN ( ... 500 id po przecinku ...) ? :o

#webdev #mysql #php #programowanie
  • 14
@Nicarim: nie, kategorie nie powtarzają się w żadnym z zagnieżdżeń. Ogólnie tak jak napisałem docelowo są to kraje, województwa, regiony, miasta (miasta są wpisane do regionów). I problem (póki co mentalny, bo kodować jeszcze tego nie zacząłem) jest w wyświetlaniu miejsc z danej lokalizacji. I o ile wyszukujemy z miasta to spoko, ale przy województwie zrobiłby się taki problem, że:

najpierw musiałbym pobrać wszystkie regiony województwa, później wszystkie miasta z wszystkich
@Domons: Jeżeli baza będzie spora, to chyba dobrze by było podzielić tak:
Przedmiot [ id, ... , idmiasta]
Kraj [id]
Wojewodztwo [id, id
kraju]
Miast [id, idwojewodztwa, idkraju]

Wiem, że część danych się powtarza, ale będzie zawsze stała i wydajna ścieżka od przedmiotu do wszystkiego w górę (miasto zawiera informacje o całej ścieżce).
@Domons: Nie wiem czy są trudności, bo nie używałem, ale na pewno dodanie nowej kategorii to nie tylko 1 insert albo i jakieś update'y

No i miałem też pisać o wersji, którą właśnie @Vetinari wrzucił. Gdyby to były jakieś "ogólne" kategorie z dowolną liczbą poziomów itp to nie, ale kraje/województwa/miasta można tak zrobić.

Ewentualnie SELECT * FROM przedmioty WHERE id_miasta IN (SELECT id FROM miasta WHERE id_wojewodztwa IN (SELECT id FROM
@qwertyu: @Vetinari: też myślałem o takim zapisie, ale nie podoba mi się właśnie ta powtarzalność danych. Myślałem też o osobnej tabelce łączącej same ID lokalizacji z ID miejsca, coś jak @Nicarim proponuje. Ale oba te rozwiązania mają taki minus, że jeśli chciałbym dodać np dzielnice miast to muszę przerabiać strukturę bazy danych...

Ewentualnie SELECT * FROM przedmioty WHERE idmiasta IN (SELECT id FROM miasta WHERE idwojewodztwa IN (SELECT
@Domons: Dwie metody:
1. WITH RECURSIVE - http://lmgtfy.com/?q=WITH+RECURSIVE+SQL
2. stwórz coś w rodzaju klucza tekstowego w którym opiszesz kategorie hierarchicznie długim stringiem: np. "1.3.56.34" (mogą być też wartości tekstowe: np. "sklep.samochod.opel.corsa" Wtedy możesz robić WHERE kategoria LIKE "1.3.56.%" (czy LIKE "sklep.samochod.opel.%") Nie będzie to mega wydajne, ale jeśli dodasz indeksy to nie powinno być dramatu.
@Domons: W guglu poszukaj mysql tree menu. Powinno być w tekście "lft", "rgt". Oznaczenia są od numeracji elementów. Najwyższy element będzie mieć lft = 1, a rgt = liczbie elementów * 2 (o ile dobrze pamiętam). Powiedzmy, że są tylko trzy(rodzic i dwa podrzędne). 1: lft=1 rgt=6, 2: lft=2 rgt=3, 3: lft=4 rgt=5. I teraz: masz id kategorii, bierzesz dane rekordu z tym id, wyciągasz $lft i $rgt, bierzesz rekordy w
@Domons: I jak robisz zapytanie, to używasz $inner = $left = $where = $pola = array() ; Kompletujesz w nich warunki, pola, dołączenia, potem implode z enterem (and w przypadku $where, przecinek w przypadku $pola) i wrzucasz do zapytania. Czysto i łatwiej ogarnąć. Inner jak robisz zawężenie ze względu na dane w innej tabeli. Where najlepiej na tabeli bazowej. Unikaj like jak ognia (chyba, że będzie mało rekordów). Przy dużych tabelach