Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Filtr produktów
Forum PHP.pl > Forum > PHP
starcode
Witam!

Piszę obecnie skrypt bazy produktów (dajmy na to komputerów, gdzie mamy monitory, laptopy, drukarki itp. itd.).
Pojawia się problem / pytanie jak wykonać filtrowanie produktów (czyli pokazywanie produktów o określonych paramterach, np.: matryca, bateria, system operacyjny, procesor, producent itp.).

Tabela produktu zawiera podstawowe dane (id, nazwa, cena, opis, zdjęcie, grupa_id, kategoria_id, podkategoria_id).
Tabela parametrów zawiera: id, id_paramteru, id_produktu, wartosc_paramteru
Tabela nazw paramterów zawiera id, nazwa

Tabela nazw param. jest połączona z tabelą param. relacją jeden do wielu (jedna nazwa param. do wielu wartości param.)
Tabela param. z tabelą produktów połączona jest relacją wiele do jednego (jeden produkt może mieć wiele paramterów)

Pytanie: Jak teraz pobrać te produkty, które mają np. system operacyjny = Windows XP i producent = ASUS?

Jest to dla mnie teraz zagadka i nie wiem jak ugryźć temat.
Spawnm
join i where w zapytaniu sql .
starcode
Możesz podać przykładowe zapytanie?

Graficznie struktura tabeli wygląda tak:

tabela nazwy_parametrow

Kod
+-------+---------------------+
|  id   | nazwa_paramteru     |
+-------+---------------------+
|   1   | system operacyjny   |
+-------+---------------------+
|   2   | producent           |
+-------+---------------------+
|   3   | procesor            |
+-------+---------------------+
|   4   | przekatna matrycy   |
+-------+---------------------+


tabela parametry (łączy wartosci paramterów z nazwami paramterow i przypisuje do konkretnego produktu)

Kod
+----------------+----------------+------------------------------+
| id_paramteru   |  id_produktu   | wartosc_paramteru            |
+----------------+----------------+------------------------------+
| 1              |   20           | Windows XP                   |
+----------------+----------------+------------------------------+
| 1              |   21           | Windows XP                   |
+----------------+----------------+------------------------------+
| 1              |   22           | Windows Vista                |
+----------------+----------------+------------------------------+
| 1              |   23           | Windows XP                   |
+----------------+----------------+------------------------------+
| 1              |   24           | Brak systemu                 |
+----------------+----------------+------------------------------+
| 2              |   20           | Asus                         |
+----------------+----------------+------------------------------+
| 2              |   21           | Acer                         |
+----------------+----------------+------------------------------+
| 2              |   22           | Asus                         |
+----------------+----------------+------------------------------+
| 2              |   23           | Asus                         |
+----------------+----------------+------------------------------+
| 2              |   24           | Asus                         |
+----------------+----------------+------------------------------+


I chcę pobrać produkty, które mają:
(`id_paramteru`='1' AND `wartosc_paramteru`='Windows XP') AND (`id_paramteru`='2' AND `wartosc_paramteru`='Asus')

Powinno zwrócić rekordy (produkty) o `id_produktu: 20 i 23.

Oczywiście istnieje jeszcze tabela produkt, która ma ID i owo ID jest wpisane w tabeli `parametry` w polu `id_produktu`
Spawnm
no to to chyba by było tak:

  1. SELECT produkty.nazwa FROM produkty, parametry WHERE produkty.id=parametry.id_produktu AND parametry.id_paramteru='1' AND parametry.wartosc_paramteru='Windows XP' AND parametry.id_paramteru='2' AND parametry.wartosc_paramteru='Asus' "


zobacz czy działa smile.gif
starcode
Cytat(Spawnm @ 23.03.2009, 10:02:06 ) *
no to to chyba by było tak:

  1. SELECT produkty.nazwa FROM produkty, parametry WHERE produkty.id=parametry.id_produktu AND parametry.id_paramteru='1' AND parametry.wartosc_paramteru='Windows XP' AND parametry.id_paramteru='2' AND parametry.wartosc_paramteru='Asus' "


zobacz czy działa smile.gif


Nie ma szans na działanie.

W tym wypadku próbujesz pobrać rekord który zarazem id_paramteru ma równe 2 i jeden, a wartosc_paramteru jest zarazem równa Asus jak i Windows XP. OR tutaj nic nie zmiania, ponieważ zwrócone zostaną zarówno produkty z Windows XP i Acerem jak i z Windowsem Vista i Asusem.
Noddi
  1. SELECT produkty.nazwa FROM (SELECT result1.id_produktu FROM (SELECT parametry.id_produktu FROM parametry WHERE parametry.wartosc_parametru='Windows XP') AS result1 INNER JOIN (SELECT parametry .id_produktu FROM parametry WHERE parametry.wartosc_parametru='Asus') AS result2 ON result1.id_produktu=result2.id_produktu) AS result INNER JOIN produkty ON result.id_produktu=produkty.id;


Ale jest to rozwiązanie mało optymalne i wydajne.
starcode
No fakt, za bardzo optymalne nie jest.

Być może jest jakieś lepsze wyjście, aby utworzyć filtr produktów?
Spawnm
a nie zastanawiałeś się może nad rozbiciem tabeli na dwie?
tabela z systemami i tabela z firmą kompa ?
wtedy sprawa była by prosta , dodatkowo była by jakaś segregacja a nie wszystko w 1 worku smile.gif
Noddi
Można zrobić też tak, myślę, że lepsze rozwiązanie:

  1. SELECT produkty.nazwa FROM (SELECT SUM(CASE WHEN parametry.wartosc_parametru='Windows XP' THEN 1 ELSE 0 END) AS windows_xp, SUM(CASE WHEN parametry.wartosc_parametru='Asus' THEN 1 ELSE 0 END) AS asus, parametry.id_produktu FROM parametry GROUP BY parametry.id_produktu) AS result INNER JOIN produkty ON result.id_produktu=produkty.id WHERE result.windows_xp=1 AND result.asus=1;
starcode
Cytat(Spawnm @ 23.03.2009, 11:10:50 ) *
a nie zastanawiałeś się może nad rozbiciem tabeli na dwie?
tabela z systemami i tabela z firmą kompa ?
wtedy sprawa była by prosta , dodatkowo była by jakaś segregacja a nie wszystko w 1 worku smile.gif


No własnie nie moge tak zrobic. Poniewaz paramterow moze byc bardzo duzo (jak pisałem, to nie beda tylko laptopy, ale i inne sprzety), wiec nie zawsze np. system operacyjny bedzie wlasciwym parametrem).

Zreszta struktura bazy wowczas zbyt wplywa na ilosc danych przechowywanych w bazie (bo umozliwia mi zapisanie tylko tych paramterow, dla ktorych sa tabele).
Spawnm
hmmm nie do końca chyba zrozumiałem ;P

przecież musisz z góry założyć czego będziesz szukać przez select.
tak więc można by wypisać jakie parametry mogły by występować i do tego dać 1 tabele
typu id_produktu, system, firma, inne
wtedy jest wszystko na swoim miejscu a nie w 1 worku , dodatkowo bardzo łatwo robić zapytania smile.gif
starcode
Całość nie bedzie na tyle statyczna, aby tworzyc tabele pod konkretne wartosci.
To musi być bardzo skalowalne. Dodanie (uzupełnienie) danych w tych tabelach w ten sposob (przynajmniej w przypadku mojego projektu) moze / czy raczej jest bardzo problematyczne i nie wiem czy wogole sensownie wykonywalne.

Oczywiscie zakladajac ze dane juz mamy w bazie - owszem, taka struktura jest bardzo wygodna.
ddiceman
Sprobuj cos w stylu
  1. SELECT
  2. id_produktu,
  3. SUM(
  4. IF(id_parametru = 1 AND wartosc_parametru = 'Windows XP', 1, /* kazdy warunek */
  5. IF(id_parametru = 2 AND wartosc_parametru = 'Asus', 1,
  6. 0
  7. )) /* tyle nawiasow zamykajacych, ile warunkow */
  8. ) AS warunek
  9. FROM parametry LEFT JOIN nazwy_parametrow ON (parametry.id_parametru = nazwy_parametrow.id)
  10. WHERE id_parametru IN (1, 2) /* to do dziala niepotrzebne, ale w celach optymalizacji */
  11. GROUP BY id_produktu
  12. HAVING warunek = 2 /* taka liczba, ile warunkow*/ ;
starcode
W sumie zapytanie powyżej jest całkiem niezłe - trzeba przyznać.

Tylko niepotrzebnie było łączone z nazwami paramterów (być może ja niepotrzebnie wogóle o tym wspomniałem zagmatwując całą systuację).

Pytanie teraz w jaki sposób połączyć to zapytanie, aby połaczyć to zapytanie nie z nazwami parametrów a z produktami:

  1. SELECT
  2. parametry.id_produktu, produkty.nazwa,
  3. SUM(
  4. IF(id_parametru = 1 AND wartosc_parametru = 'Windows XP', 1,
  5. IF(id_parametru = 2 AND wartosc_parametru = 'Asus', 1,
  6. 0
  7. ))
  8. ) AS warunek, MIN(cena) AS cena_minimalna
  9. FROM parametry LEFT JOIN produkty ON (parametry.id_produktu = produkty.id_produktu)
  10. WHERE id_parametru IN (1, 2) AND produkty.STATUS='1'
  11. GROUP BY id_produktu
  12. HAVING warunek = 2


Ale niestety nie działa? Co źle?
ddiceman
  1. SELECT
  2. parametry.id_produktu, produkty.nazwa,
  3. SUM(
  4. IF(id_parametru = 1 AND wartosc_parametru = 'Windows XP', 1,
  5. IF(id_parametru = 2 AND wartosc_parametru = 'Asus', 1,
  6. 0
  7. ))
  8. ) AS warunek, MIN(cena) AS cena_minimalna, COUNT(produkty.id) AS warunek2
  9. FROM parametry LEFT JOIN produkty ON (parametry.id_produktu = produkty.id_produktu AND produkty.STATUS='1')
  10. WHERE id_parametru IN (1, 2)
  11. GROUP BY id_produktu
  12. HAVING warunek = 2 AND warunek2 = 2

Zeby nie laczyc nieaktywnych produktow, bo wtedy nie wyjdzie Ci to wyliczenie warunek i zeby zliczac tylko zlaczenia z aktywnymi warunek2
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.