Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zapytanie wyszukujące na podstawie parametrów (tak jak na allegro)
Forum PHP.pl > Forum > Bazy danych > MySQL
lorak110786
Witam. Mam następujący problem:
Są 2 tabele:
produkty, parametry

w tabeli 'produkty' są pola:
id_produktu, nazwa

w tabeli 'parametry' są pola:
id_produktu, parametr, wartosc

Omawiając. Każdy produkt ma kilka parametrów. Każdy parametr ma jakąś wartość. Mam 3 produkty: pr1, pr2, pr3. Mam też ogólnie 3 parametry: wys, szer, waga. Łącznie w tabeli 'parametry' mam 9 rekordów, po 3 pary >parametr i wartość parametru< dla każdego z produktów.

Chciałbym napisać takie zapytanie które wybierze mi produkty spełniające WSZYSTKIE określone warunki w jednym zapytaniu czyli np: 'wys' BETWEEN 30 AND 100, oraz 'szer' BETWEEN 60 AND 100 oraz 'waga' BETWEEN 10 AND 100

Próbowałem już kombinować na różne sposoby, ale nie chce mi wyjść. Otrzymuję albo wyniki produktów spełniających dowolne kryterium, lub jeśli w HAVING użyję "AND" - brak wyników, co jest oczywiste gdyż nie ma dwóch rekordów spełniających warunki na AND.

  1. SELECT *
  2. FROM products
  3. LEFT JOIN products_values vals USING(id_product)
  4. HAVING (vals.id_label=61 AND vals.value BETWEEN 100 AND 500) OR (vals.id_label=63 AND vals.value BETWEEN 15 AND 30)


Ma ktoś na to jakiś mądry sposób? Z góry dziękuję za podpowiedzi.
TheTester
Nie wiem jak to zadziała, bo pisane bez sprawdzania, ale ja bym to chyba tak zrobił:

  1. SELECT * FROM products p, products_values v WHERE p.id=v.id_product AND ((v.id_label=61 AND v.value BETWEEN 100 AND 50) OR (v.id_label=63 AND v.value BETWEEN 15 AND 30))
lorak110786
No to jest pierwsza rzecz jaką próbowałem zrobić. Niestety wybiera źle. Wybiera rekordy które spełniają dowolne z warunków (gdyż użyte jest OR).
TheTester
Hmm...Opierałem się na tym przykładzie, co wstawiłeś. Gdybym chciał pobrać wszystkie produkty, które spełniają pewne założenia, to bym zrobił coś takiego:

  1. SELECT * FROM products p, products_values v WHERE p.id=v.id_product AND v.value1 BETWEEN 50 AND 100 AND v.value2 BETWEEN 15 AND 30

Coś takiego powinno zwrócić wszystkie produkty, których value1 zawiera się w przedziale 50-100 a value2 w przedziale 15-30.
nospor
Trzeba zastosować podobne rozwiązanie jak tu:
http://forum.php.pl/index.php?s=&showt...st&p=793421
sniver
w serwisie erobay.pl zastosowałem taki oto format:

Kategorie produktów, a do każdej (zaczynając od rodzica - potomkowie dziedziczą parametry) dodałem parametry.

Każdy z nich zadeklarowałem w/g takich wartości jak: checkbox, select i range.

Każde z nich ma na celu dać użytkownikowi pożądany sposób przefiltrowania informacji oraz przy wysłaniu formularza przygotowanie odpowiedniego zapytania do bazy danych.

I tak w przypadku jeśli parametrem jest checkbox wtedy każdy kolejny parametr z tej grupy rozdzielany jest jako OR (tak by dopasować maksymalnie dużo pasujących wyników).
Gdy wybierze ktoś select to wtedy tylko i wyłącznie wybrana wartość jest brana pod uwagę...
Range - czyli zakres, wtedy system wypisze pole w stylu Cena od: [____] do: [____] - i analogicznie dobierze zapytanie które określi zakres smile.gif

Tyle w teorii..

W praktyce wygląda to tak:

  1. CREATE TABLE IF NOT EXISTS `parametr` (
  2. `PRM_Id` int(11) NOT NULL AUTO_INCREMENT,
  3. `CAT_Id` int(11) NOT NULL,
  4. `PRM_Name` varchar(45) NOT NULL,
  5. `PRM_FormName` varchar(45) NOT NULL,
  6. `PRM_Type` enum('select','checkbox','range') NOT NULL,
  7. `PRM_MultiSelect` int(1) NOT NULL DEFAULT '0',
  8. `PRM_Value` text NOT NULL,
  9. `PRM_Sort` int(11) NOT NULL DEFAULT '0',
  10. `PRM_Active` tinyint(1) NOT NULL DEFAULT '1',
  11. PRIMARY KEY (`PRM_Id`),
  12. KEY `PARAMERTS` (`CAT_Id`,`PRM_Active`),
  13. KEY `PRM_FormName` (`PRM_FormName`)
  14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;


Opis pól:
PRM_Id - id rekordu w tej tabeli
CAT_Id - id kategorii od której zaczyna się ten parametr (wszystkie kategorie dzieci będą dziedziczyć ten parametr)
PRM_Name - nazwa pola widzialna dla użytkownika: np. Kolor
PRM_FormName - nazwa pola w formularzu
PRM_Type - czyli to ten wybór z wspomnianych informacji powyżej...
PRM_MultiSelect - to nie jest potrzebne do tego zagadnienia (czyli można wywalić)
PRM_Value - tak samo (można pominąć)
PRM_Sort - kierunek sortowania (wartość liczbowa)
PRM_Active - wartość 1 jesli parametr aktywny i widoczny, 0 jeśli nieaktywny i niewidoczny


2 tabelą są wartości tych parametrów:
  1. CREATE TABLE IF NOT EXISTS `parametrvalue` (
  2. `PRV_Id` int(11) NOT NULL AUTO_INCREMENT,
  3. `PRM_Id` int(11) NOT NULL,
  4. `PRV_Value` varchar(255) NOT NULL,
  5. `PRV_Sort` int(11) NOT NULL DEFAULT '0',
  6. PRIMARY KEY (`PRV_Id`),
  7. KEY `parametr` (`PRM_Id`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;


PRV_Id - id rekordu w tej tabeli
PRM_Id - id parametru (z poprzedniej tabeli)
PRV_Value - wartość widoczna dla użytkownika, np. Parametr Kolor, wartości: różowy, zielony, niebieski...
PRV_Sort - ustawienie kolejności sortowania (wartość liczbowa)


i ostatnia tabela z parametrami przypisanymi do samych produktów:

  1. CREATE TABLE IF NOT EXISTS `productsparametr` (
  2. `PRP_Id` int(11) NOT NULL AUTO_INCREMENT,
  3. `PRD_Id` int(11) NOT NULL,
  4. `PRV_Id` int(11) NOT NULL,
  5. `PRP_Value` varchar(45) NOT NULL,
  6. PRIMARY KEY (`PRP_Id`),
  7. KEY `PRODUCT` (`PRD_Id`),
  8. KEY `VALUE` (`PRV_Id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


Opis pól:
PRP_Id - id rekordu
PRD_Id - id produktu
PRV_Id - id wartości (po tym dojdziecie jaki to parametr)
PRP_Value - wartość dla pola range (zakres)

To by było tyle jeśli chodzi o mój układ.
Napisanie samego zapytania chyba nie powinno stanowić problemu, w razie czego go tu wkleje...

Pozdo 600 i niech moc będzie z wami blinksmiley.gif
lorak110786
@sniver
Mam bardzo podobny układ tabel. Prawie identyczny. Niemniej właśnie z zapytaniem mam problem. Mógłbyś się podzielić?
sniver
Pomijając tabele z bazą produktów, cenami, promocjami itp. duperelami u mnie mniej więcej wygląda to tak:

To zapytanie liczące ilość produktów z wybranymi parametrami (wybrałem je bo jest krótsze, a długość o wiele mniejsza smile.gif)

  1. SELECT
  2. ceil(count(0)/10) AS `licz`
  3.  
  4. FROM
  5. `products` AS `p`
  6. JOIN `productsparametr` AS `pp1` ON (`pp1`.`PRD_Id` = `p`.`PRD_Id`)
  7. JOIN `productsparametr` AS `pp2` ON (`pp2`.`PRD_Id` = `p`.`PRD_Id`)
  8. JOIN `productsparametr` AS `pp3` ON (`pp3`.`PRD_Id` = `p`.`PRD_Id`)
  9.  
  10. WHERE
  11. (`p`.`CAT_Id` IN (53))
  12. AND (`p`.`PRD_Deleted` = 0)
  13. AND (`p`.`PRD_Active` = 1)
  14. AND (
  15. (`pp1`.`PRV_Id` IN (48,49))
  16. AND (`pp1`.`PRP_Value` BETWEEN '3' AND '10')
  17. )
  18. AND (`pp2`.`PRV_Id` = 50)
  19. AND (`pp3`.`PRV_Id` IN (1,2,3))


każde podłączenie tabeli za pomocą join jest generowane przez skrypt php, co w konsekwencji buduje zapytanie sql. Zapytanie zostało wykonane ze strony: http://www.erobay.pl/kategorie/53/Biustonosze.html

więc możesz sobie zobaczyć względem parametrów jak sie to składa w całość smile.gif

prawde mówiąc to troche sie napociłem by to wymyśleć i by działało, względem wyszukiwarki i kategorii w głąb. Oto mój sposób - może nie najlepszy i nie najbardziej efektywny ale działa ;]

PS. Nie wykorzystuje parametrów póki co, ale ten sposób napewno działa - poprostu parametry nie są przypisane do produktów biggrin.gif
lorak110786
@sniver
Zrobiłem tak jak u Ciebie. Buduję w ten sposób duże zapytanie. Zapytanie wykonuje się całkiem szybko a sposób jest nader skuteczny i przede wszystkim działa:)

  1. SELECT products.id_product, products.name, products.id_category, categories.value AS category, (
  2.  
  3. SELECT ROUND( MAX( price ) , 2 )
  4. FROM providers_products priceproviders
  5. WHERE products.id_product = priceproviders.id_product
  6. ) AS maxprice, (
  7.  
  8. SELECT ROUND( MIN( price ) , 2 )
  9. FROM providers_products priceproviders
  10. WHERE products.id_product = priceproviders.id_product
  11. ) AS minprice
  12. FROM products products
  13. JOIN treecat AS categories
  14. USING ( id_category )
  15. JOIN products_values AS param61
  16. USING ( id_product )
  17. JOIN products_values AS param63
  18. USING ( id_product )
  19. JOIN products_values AS param64
  20. USING ( id_product )
  21. WHERE products.id_category
  22. IN ( 115 )
  23. AND (
  24. param61.id_label = '61'
  25. AND param61.value
  26. BETWEEN 100
  27. AND 500
  28. )
  29. AND (
  30. param63.id_label = '63'
  31. AND param63.value
  32. BETWEEN 15
  33. AND 30
  34. )
  35. AND (
  36. param64.id_label = '64'
  37. AND param64.value
  38. IN ( 0, 1, 3 )
  39. )



Bardzo dziękuję Ci za pomoc. Serdecznie pozdrawiam:)
sniver
nie ma za co - w takim razie myślę że ktoś może zamknąc haha.gif
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.