Problem z zaptytaniem SQL
Marek - 13-11-2006 00:43
Problem z zaptytaniem SQL
Witam,
Wykonałem w HTMLu formularz wyszukiwania produktów. Są w nim checkboxy określające pewne cechy tych produktów. Chciałbym wyłonić z bazy produktów, te które łącznie spełniają zaznaczone cechy. Chyba jest zbyt późno bo nie wiem jak to zrobić w przypadku gdy struktura jest jak poniżej (w uproszczeniu):
create table produkt ( produkt_id primary key, .... );
create table lista_wszystkich_mozliwych_cech ( lista_wszystkich_mozliwych_cech_id primary_key, nazwa_cechy text, .... );
create table cecha ( cecha_id primary key, lista_wszystkich_mozliwych_cech_id foreign key lista_wszystkich_mozliwych_cech(lista_wszystkich_m ozliwych_cech_id), produkt_id foreign key references produkt (produkt_id), wartosc_cechy text );
Generalnie jeśli jakaś cecha występuje w danym produkcie to w tabeli cech powstaje rekord powiącany z danym produktem i z nazwą tejże cechy. Produkt w ten sposób może posiadać zmienną ilość cech. Z formularza HTML odrzymuję listę wartości lista_wszystkich_mozliwych_cech_id, które zostały "kliknięte" w parametrach wyszukiwarki. No i nie mam koncepcji co dalej ...
-- Pozdrawiam, Marek
Marek - 13-11-2006 00:43
Uzupełnienie.
Być może to co wczoraj napisałem nie jest jasne a do tego narobiłem ze zmęczenia błędów. Dlatego dorzucę przykład obrazujący zachowanie się tej struktury danych i to co chcę osiągnąć. Załóżmy, że mamy dwa produkty: telefon komórkowy oraz używane kapcie. Załóżmy, że mamy dostępne następujące cechy produktów: GPRS, kolor oraz aromat. Przypisujemy telefonowi cechę GPRS i kolor a kapciom: kolor i aromat. W efekcie w tabeli "cecha" mamy 4 rekrdy: dwa związane z telefonem i dwa z kapciami. Jeśli uzytkownik w wyszukiwarce zaznaczy opcję "kolor" to pytanie SQL powinno zwrócić oba produkty. Jeśli dodatkowo zostanie zaznaczone pole "aromat" to tym razem powinien być zwrócony jedynie 1 rekord: kapie.
Mitis - 13-11-2006 00:43
Aaye Marek,
> Uzupełnienie. > > Być może to co wczoraj napisałem nie jest jasne a do tego narobiłem ze > zmęczenia błędów. Dlatego dorzucę przykład obrazujący zachowanie się > tej struktury danych i to co chcę osiągnąć. Załóżmy, że mamy dwa > produkty: telefon komórkowy oraz używane kapcie. Załóżmy, że mamy > dostępne następujące cechy produktów: GPRS, kolor oraz aromat. > Przypisujemy telefonowi cechę GPRS i kolor a kapciom: kolor i aromat. > W efekcie w tabeli "cecha" mamy 4 rekrdy: dwa związane z telefonem i > dwa z kapciami. Jeśli uzytkownik w wyszukiwarce zaznaczy opcję "kolor" > to pytanie SQL powinno zwrócić oba produkty. Jeśli dodatkowo zostanie > zaznaczone pole "aromat" to tym razem powinien być zwrócony jedynie 1 > rekord: kapie. >
jeden parametr SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;
dwa parametry SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1 AND t2.column3=3
nie pamietam teraz dokladnie, ale chyba kolejnosc warunkow po WHERE jest obojetna
Adam Płaszczyca - 13-11-2006 00:43
On Wed, 11 Oct 2006 10:03:35 +0200, "Marek" <marek1967@spam.interia.pl> wrote:
>dwa związane z telefonem i dwa z kapciami. Jeśli uzytkownik w wyszukiwarce >zaznaczy opcję "kolor" to pytanie SQL powinno zwrócić oba produkty. Jeśli >dodatkowo zostanie zaznaczone pole "aromat" to tym razem powinien być >zwrócony jedynie 1 rekord: kapie.
Tutaj trzeba użyć dynamicznego SQL-a, bo zmieniasz ilośc parametrów, albo też obsłużyć całą rzecz programowo.
Tak na szybko można zrobić to tak: Dla jednej cechy:
SELECT distinct produkt_id from cecha AS C1 where C1.lista_wszystkich_mozliwych_cech_id=<cecha_jaka_ nas_interesuje_1>
Dla dwóch robimy tak: SELECT distinct produkt_id from cecha AS C1 JOIN cecha AS C2 ON C1.produkt_id=C2.produkt_id where C1.lista_wszystkich_mozliwych_cech_id=<cecha_jaka_ nas_interesuje_1> AND C2.lista_wszystkich_mozliwych_cech_id=<cecha_jaka_ nas_interesuje_2>
Dla trzech tak: SELECT distinct produkt_id from cecha AS C1 JOIN cecha AS C2 ON C1.produkt_id=C2.produkt_id JOIN cecha AS C3 ON C1.produkt_id=C3.produkt_id where C1.lista_wszystkich_mozliwych_cech_id=<cecha_jaka_ nas_interesuje_1> AND C2.lista_wszystkich_mozliwych_cech_id=<cecha_jaka_ nas_interesuje_2> AND C2.lista_wszystkich_mozliwych_cech_id=<cecha_jaka_ nas_interesuje_3>
I tak dalej.
-- ___________ (R) /_ _______ Adam 'Trzypion' Płaszczyca (+48 502) 122 688 ___/ /_ ___ ul. Na Szaniec 23/70, 31-560 Kraków _______/ /_ http://trzypion.oldfield.org.pl/fotki/Ponidzie_2006/ ___________/ mail: _555@irc.pl GG: 3524356
Marek - 13-11-2006 00:43
> jeden parametr > SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1; > > dwa parametry > SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1 AND > t2.column3=3 > > nie pamietam teraz dokladnie, ale chyba kolejnosc warunkow po WHERE jest > obojetna
Witaj,
Nie bardzo załapałem Twoje intencje. To co nazwałeś column1, column2 i column3 to jest ta sama kolumna u mnie nazwana lista_wszystkich_mozliwych_cech_id. W takim razie jeśli szukamy rekordu, który ma jednocześnie wartość pola ustawioną na 2 i 3 to z pewnością nie znajdziemy go.
Marek - 13-11-2006 00:43
Hmmm ... troszkę to zawiłe. Oczywiście mogę dynamicznie budować SQL i to właśnie robię. Boję się tylko, że przy takim rozwiązaniu kliknięcie np. 50 opcji zatka mi serwer obliczeniami. W międzyczasie obszedłem ten problem poniższą strukturą (PHP) lecz nadal nie wiem czy to nie jest tylko obejściem:
SELECT * FROM product, ...inne relacje WHERE ... AND product_id IN (SELECT product_id FROM cecha WHERE lista_wszystkich_mozliwych_cech_id IN (".join(",",$array).") GROUP BY product_id HAVING count(product_id)=".count($array).")";
Zmienna $array zawiera kliknięte przez usera checkboxy. Jest to lista ID zaznaczonych cech. Jeśli ktoś zaznaczył np. 10 cech to szukam wszystkich produktów należących do jakiejkolwiek z tych cech. Jeśli znalezionych produktów o danym ID jest dokładnie tyle ile kliknięto cech to znaczy, że dany produkt posiada wszystkie te cechy, a więc spełnia kryterium wyszukiwania. To działa lecz nie lubię konstrukcji z IN gdyż są nieefektywne ponoć. Engine musi wybrać wszystkie rekordy po lewej i po prawej stronie IN i potem porównuje wyniki. Dlatego oczekuję jeszcze innego rozwiązania, o ile istnieje.
Paweł Matejski - 13-11-2006 00:43
Marek wrote: > Hmmm ... troszkę to zawiłe. Oczywiście mogę dynamicznie budować SQL i to > właśnie robię. Boję się tylko, że przy takim rozwiązaniu kliknięcie np. > 50 opcji zatka mi serwer obliczeniami. W międzyczasie obszedłem ten > problem poniższą strukturą (PHP) lecz nadal nie wiem czy to nie jest > tylko obejściem: > > > SELECT * FROM product, ...inne relacje WHERE ... AND product_id IN > (SELECT product_id FROM cecha > WHERE lista_wszystkich_mozliwych_cech_id IN (".join(",",$array).") > GROUP BY product_id > HAVING count(product_id)=".count($array).")"; > > Zmienna $array zawiera kliknięte przez usera checkboxy. Jest to lista ID > zaznaczonych cech. Jeśli ktoś zaznaczył np. 10 cech to szukam wszystkich > produktów należących do jakiejkolwiek z tych cech. Jeśli znalezionych > produktów o danym ID jest dokładnie tyle ile kliknięto cech to znaczy, > że dany produkt posiada wszystkie te cechy, a więc spełnia kryterium > wyszukiwania. To działa lecz nie lubię konstrukcji z IN gdyż są > nieefektywne ponoć. Engine musi wybrać wszystkie rekordy po lewej i po > prawej stronie IN i potem porównuje wyniki. Dlatego oczekuję jeszcze > innego rozwiązania, o ile istnieje.
Heh... podobno, gdzieś napisali... Pamiętaj, jeśli nie znasz źródła, albo wytłumaczenia dlaczego tak się dziej, nie jesteś w stanie zweryfikować takiej informacji. A to nie jest prawdą przynajmniej dla kilku baz. Ja rozumiem, żeby Ci to zapytanie działało wolno, albo miał z nim inne z nim problemy. Ale tak z góry założyć, że jest złe...
-- P.M.
Marek - 13-11-2006 00:43
> Heh... podobno, gdzieś napisali... Pamiętaj, jeśli nie znasz źródła, albo > wytłumaczenia dlaczego tak się dziej, nie jesteś w stanie zweryfikować > takiej > informacji. A to nie jest prawdą przynajmniej dla kilku baz. > Ja rozumiem, żeby Ci to zapytanie działało wolno, albo miał z nim inne z > nim > problemy. Ale tak z góry założyć, że jest złe...
No dobrze, to pozostaje mi niczego nie zmieniać :-) Dzięki za zaangażowanie.
elessar - 13-11-2006 00:43
Marek napisał(a): > Hmmm ... troszkę to zawiłe. Oczywiście mogę dynamicznie budować SQL i to > właśnie robię. Boję się tylko, że przy takim rozwiązaniu kliknięcie np. > 50 opcji zatka mi serwer obliczeniami. W międzyczasie obszedłem ten > problem poniższą strukturą (PHP) lecz nadal nie wiem czy to nie jest > tylko obejściem: > > > SELECT * FROM product, ...inne relacje WHERE ... AND product_id IN > (SELECT product_id FROM cecha > WHERE lista_wszystkich_mozliwych_cech_id IN (".join(",",$array).") > GROUP BY product_id > HAVING count(product_id)=".count($array).")"; > > Zmienna $array zawiera kliknięte przez usera checkboxy. Jest to lista ID > zaznaczonych cech. Jeśli ktoś zaznaczył np. 10 cech to szukam wszystkich > produktów należących do jakiejkolwiek z tych cech. Jeśli znalezionych > produktów o danym ID jest dokładnie tyle ile kliknięto cech to znaczy, > że dany produkt posiada wszystkie te cechy, a więc spełnia kryterium > wyszukiwania. To działa lecz nie lubię konstrukcji z IN gdyż są > nieefektywne ponoć. Engine musi wybrać wszystkie rekordy po lewej i po > prawej stronie IN i potem porównuje wyniki. Dlatego oczekuję jeszcze > innego rozwiązania, o ile istnieje.
heh widze ze wykorzystales moje zapytanie :-) Co do IN to jest tak samo nieefektywne jak lista_wszystkich_mozliwych_cech_id = 1 or lista_wszystkich_mozliwych_cech_id = 2 ...
zanotowane.pldoc.pisz.plpdf.pisz.pleffulla.pev.pl
|
jak to =?ISO-8859-2?Q?zrobi=E6=2E=2E=2E=3F_TSQL_sql_server?==?ISO-8859-2?Q?_?=
[MSSQL2000] Problem z =?ISO-8859-2?Q?tabel=B1/indeksem/zapytanie?==?ISO-8859-2?Q?m_czy_b=B3=B1d_w_bazie_danych=2E=2E=2E?=
Jak =?windows-1250?Q?pobra=E6_szacowan=B9_wielko=9C=E6_zbiory_wy nikowego_w_MS?==?windows-1250?Q?_SQL_2005=3F?=
=?iso-8859-2?Q?=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkcje_t ylko_raz_dla?==?iso-8859-2?Q?_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?=
[MSSQL] =?ISO-8859-2?Q?zgodno=B6ci_z_licencjami_Microsoft_?==?ISO-8859-2?Q?SQL_Server?=
=?ISO-8859-2?Q?k=B3opot_z_uruchomieniem_MY_SQL_dla_C?==?ISO-8859-2?Q?MS_i_CRM_na_Fedora_Core_3?=
Oracle PL/SQL Wstawianie =?ISO-8859-2?Q?wynik=F3w_kolekcji_d?==?ISO-8859-2?Q?o_tabeli?=
[MSSQL] ACCESS - SQL =?ISO-8859-2?Q?B=B3ad_w_konwersji_lic?==?ISO-8859-2?Q?zb?=
=?iso-8859-2?Q?=5Bmssql=5D_Zapytania_rekurencyjne__-_czy_sk=B3adnia_sql?==?iso-8859-2?Q?_co=B6_takiego_przewiduje_=3F?=
[Oracle PL/SQL] Cursor i zapis =?ISO-8859-2?Q?rekord=F3w_do_?==?ISO-8859-2?Q?kolejnych_plik=F3w?=
zanotowane.pldoc.pisz.plpdf.pisz.plwawa19wwa91.pev.pl
Cytat
Decede mihi sole - nie zasłaniaj mi słonca. Gdy kogoś kochasz, jesteś jak stworzyciel świata - na cokolwiek spojrzysz, nabiera to kształtu, wypełnia się barwą, światłem. Powietrze przytula się do ciebie, choćby był mróz, a ty masz w sobie tyle radości, że musisz ją rozdawać wokoło, bo się w tobie nie mieści Hoc fac - tak czyń. A tergo - od tyłu; z tyłu. I czarne włosy posiwieją. Safona |
|