2014-10-28 10 views
5

Próbuję napisać stronę z produktami na podstawie kryteriów od użytkownika. Poniższe pola są przekazywane domyślnie:MySQL Powracanie wierszy na podstawie dodatkowych parametrów PDO

  • QString (aby dopasować nazwę produktu/opis)
  • maxPrice/minPrice (zrobić od cen w tabeli)
  • minDate/MaxDate (aby szukać produkty między terminami dostępność)

Powyższe daje mi wartości zwracane.

Kolejna para pola są opcjonalne i dodał poprzez jQuery na podstawie kategorii:

  • Kategoria: category_id który pasuje powrotem do deals.deals_category_id (ten nadal działa)

Based w kategorii mogą pojawiać się dodatkowe atrybuty (takie jak umowy z dostawcami usług, producent), które będą dynamicznie widoczne w interfejsie użytkownika. Od tego momentu klient może za pomocą pól wyboru wybrać producentów, którymi są zainteresowani i dostawcę usług.

Moi Tabele zawierają:

  • oferty (zawiera produkty z deal_category_id)
  • Kategorie (Wszystkie oferty są połączone z kategorii)
  • Category_attributes (dodatkowe atrybuty na kategorie Jeśli produkt jest. załadowane do kategorii będą również dostarczane z dodatkowymi selektorami atrybutów
  • Deal_attribute_options (Zawiera relacje powiązane opcje w oparciu o atrybut (gdzie atrybutem mogą być usługodawcy i atrybut opti mogą mieć AT & T, t-Mobile itp.).
  • Deal_attribute_values ​​(Zawiera wartości wybranych opcji atrybutów podczas tworzenia produktu Powiedzmy, że utworzyłem nowy telefon komórkowy i wybrałem kategorię telefony komórkowe, produkt będzie musiał podać wartości dla opcji atrybut_. Będą one otrzymywać listę np. sieci komórkowe lub producenci i powiązać producenta produktu z tym konkretnym producentem ..

Do tej pory posiadam w bazie danych kilka produktów, z których każdy jest powiązany z kategorią i na podstawie atrybutów powiązanych z tą kategorią. kategoria, każdy produkt wybrałby wartość dla każdej opcji atrybutu.Jeżeli istniałyby 2 atrybuty (producent, sieć komórkowa), każdy produkt miałby wartość w deal_valename_values ​​łączącą dealeid, attribute_id i th en wybraną wartość (aby produkty mogły być producentem Samsunga, a Vodafone jako usługodawcą).

Co teraz próbuję zrobić, opiera się na kwerendzie wyszukiwania, zwróć powiązane wiersze na podstawie filtrowania z przodu. Po zmianie formy na interfejsie, nastąpi przekształcenie do postaci szeregowej wartości i za pomocą ajax'a zwrócimy prawidłowe produkty na podstawie tych zapytań.

Dostaję go do pracy doskonale, z wyjątkiem wartości atrybut_wartości. Podejrzewam, że ma to coś wspólnego z moją klauzulą ​​IN() w zapytaniu, ale mam nadzieję, że ktoś może mi pomóc tutaj z tym, co robię źle.

Oto metoda model:

public function getDeals() { 

    $select = array(); 
    $tables = array(); 
    $where = array(); 
    $values = array(); 

    // Default to get all deal rows: 
    $select[] = "`deals`.*"; 
    $tables[] = "`deals`"; 

    // Get the category Name AND ID 
    $select[] = "`deal_categories`.`name` AS `catName`"; 
    $tables[] = "`deal_categories`"; 
    $where[] = "`deals`.`deal_category_id`=`deal_categories`.`id`"; 

    // Look if a category was selected: 
    $cat = $_POST['category']; 
    if ($cat != "") { 
     $where[] = "`deals`.`deal_category_id`=?"; 
     $values[] = $cat; 
    } 

    // Assign a query of the deal by string: 
    if ($_POST['searchDeals'] != "") { 
     $where[] = "CONCAT_WS(' ',`deals`.`name`,`deals`.`description`) LIKE ?"; 
     $values[] = "%" . str_replace(" ", "%", htmlspecialchars($_POST['searchDeals'])) . "%"; 
    } 

    // Process Min/Max PRicing: 
    if (isset($_POST['minPrice'])) { 
     $minPrice = intval($_POST['minPrice']); 
     $where[] = "`deals`.`price` >= ?"; 
     $values[] = $minPrice; 
    } 

    if (isset($_POST['maxPrice'])) { 
     $maxPrice = intval($_POST['maxPrice']); 
     $where[] = "`deals`.`price` <= ?"; 
     $values[] = $maxPrice; 
    } 

    // PRocess the min/max dates: 
    if (isset($_POST['minDate'])) { 
     $minDate = $_POST['minDate']; 
     $where[] = "`deals`.`start_date` >= ?"; 
     $values[] = $minDate; 
    } 

    if (isset($_POST['maxDate'])) { 
     $maxDate = $_POST['maxDate']; 
     $where[] = "`deals`.`end_date` <= ?"; 
     $values[] = $maxDate; 
    } 

    if (isset($_POST['attr']) && valid_array($_POST['attr'])) { 
     $tables[] = "`deal_attribute_values`"; 
     foreach ($_POST['attr'] AS $attrID => $checked) { 
      $values[] = $attrID; 
      $where_condition = "`deals`.`id`=`deal_attribute_values`.`deal_id` 
     AND `deal_attribute_values`.`deal_attribute_id`=? 
     AND `deal_attribute_values`.`value` IN ("; 
      $bind_placeholder = array(); 
      foreach ($checked as $val) { 
       $bind_placeholder[] = "?"; 
       $values[] = $val; 
      } 
      $where_condition .= implode(',', $bind_placeholder) . ")"; 
      $where[] = $where_condition; 
     } 
    } 

    $sql = "SELECT " . implode(", ", $select) . " FROM " . implode(",", $tables) . " WHERE " . implode(" AND ", $where); 

    return $this->get($sql, $values); 
} 

Oto próbka POST tym atrybutów (zauważ, że kluczem 3 i 4) reprezentuje zbiór atrybutów (producent i dostawca usług). Wartości dla nich to sprawdzone opcje, przez które chcemy działać IN().

Array 
(
[searchDeals] => 
[category] => 2 
[attr] => Array 
    (
     [3] => Array 
      (
       [0] => 8 
       [1] => 9 
       [2] => 12 
       [3] => 10 
      ) 

     [4] => Array 
      (
       [0] => 4 
       [1] => 7 
       [2] => 5 
      ) 

    ) 

[minPrice] => 100000 
[maxPrice] => 9500 
[minDate] => 2014-10-26 00:00:00 
[maxDate] => 2014-11-30 00:00:00 
) 

Tutaj jest wyprowadzany SQL w oparciu o wyżej (aktualizowane na podstawie aktualizacji kodu):

SELECT `deals`.*, `deal_categories`.`name` AS `catName` FROM `deals`,`deal_categories`,`deal_attribute_values` WHERE `deals`.`deal_category_id`=`deal_categories`.`id` AND `deals`.`deal_category_id`=? AND `deals`.`price` >= ? AND `deals`.`price` <= ? AND `deals`.`start_date` >= ? AND `deals`.`end_date` <= ? AND `deals`.`id`=`deal_attribute_values`.`deal_id` AND `deal_attribute_values`.`deal_attribute_id`=? AND `deal_attribute_values`.`value` IN (?,?,?,?) AND `deals`.`id`=`deal_attribute_values`.`deal_id` AND `deal_attribute_values`.`deal_attribute_id`=? AND `deal_attribute_values`.`value` IN (?,?,?) 

A oto wartości PDO:

Array 
(
[0] => 2 
[1] => 100000 
[2] => 9500 
[3] => 2014-10-26 00:00:00 
[4] => 2014-11-30 00:00:00 
[5] => 3 
[6] => 8 
[7] => 9 
[8] => 12 
[9] => 10 
[10] => 4 
[11] => 4 
[12] => 7 
[13] => 5 
) 

Mogę potwierdzić, że otrzymuję wyniki do momentu wprowadzenia atrybutów. Nadal mogę uzyskać wynik, jeśli odznaczam wszystkie atrybuty (zarówno dla producenta, jak i usługodawcy) i wybieram tylko 1 atrybut np. "Apple", który następnie zwraca pojedynczy produkt, ale jeśli wybiorę powiązanego dostawcę usług, nie ma wyniki.

Zasadniczo z atrybutami chcę wybrać wiersz, jeśli wartość tego produktu w tabeli wartości atrybutów mieści się w atrybutach w klauzuli IN(). Ponieważ będzie wiele atrybutów opartych na kategorii i wiele produktów powinno zostać zwróconych, jeśli utrzymam Apple, Samsung i Vodacom/MTN jako SP. Jeśli produkt jest samsung i Vodacom/MTN powinien powrócić lub jeśli nie wybrano producenta, a my wybieramy Vodacom/MTN tylko jako SP, powinien on zwracać wszystkie telefony, które są albo MTN/Vodacom. Nawet jeśli nie ma Vodacom, powinien przynajmniej zwrócić wszystkie MTN.

Proszę dać mi znać, jeśli potrzebujesz dodatkowej pomocy/informacji. Starałem się mieć jak najwięcej szczegółów tutaj więc nadzieję, że każdy rozumie :)

** ODPOWIEDŹ UPDATE **

Zrobiłem 2 zmiany kodu wysłana przez Alex, który działa na mojej stronie! Dziękuję Alex :)

if (isset($_POST['attr']) && valid_array($_POST['attr'])) { 
     foreach ($_POST['attr'] AS $attrID => $checked) { 
      $current_table = "`deal_attribute_values` AS `dav" . $attrID."`"; 
      $asName = "`dav".$attrID."`"; 
      $values[] = $attrID; 
      $where_condition = "`deals`.`id`=".$asName.".`deal_id` 
     AND " . $asName . ".`deal_attribute_id`=? 
     AND " . $asName . ".`value` IN ("; 
      $bind_placeholder = array(); 
      foreach ($checked as $val) { 
       $bind_placeholder[] = "?"; 
       $values[] = $val; 
      } 
      $where_condition .= implode(',', $bind_placeholder) . ")"; 
      $where[] = $where_condition; 
      $tables[] = $current_table; 
     } 
    } 
+0

1 wszystkich, bardzo szczegółowe pytania. +1 za to. – itachi

Odpowiedz

1

wierzę, że masz rację co do tego, że problem jest w klauzuli IN. Występuje problem z przygotowanymi instrukcjami i wartościami dla klauzuli IN. Nie można przekazać całego warunku klauzuli IN jako jednego parametru, ponieważ automatycznie ucieknie on jako całość, a nie jako pojedyncze wartości.

Więc trzeba:

if (isset($_POST['attr']) && valid_array($_POST['attr'])) { 
    $tables[] = "`deal_attribute_values`"; 
    foreach ($_POST['attr'] AS $attrID => $checked) { 
     $str = implode(", ", $checked); 
     $where[] = "`deals`.`id`=`deal_attribute_values`.`deal_id` 
     AND `deal_attribute_values`.`deal_attribute_id`=? 
     AND `deal_attribute_values`.`value` IN (?)"; 
     $values[] = $attrID; 
     $values[] = $str; 
    } 
} 

Kiedy wiążą parametr oświadczenie $str będzie upakować całą $str w cudzysłowie dlatego IN posiadających tylko jedną wartość zamiast wartości oddzielonych przecinkami.

Masz 2 opcje:

  1. Albo dołączyć $str na zapytania bez wiązania go
  2. dodać wystarczającą ? klauzuli IN dla każdej wartości IN pragniesz tak:
 
    foreach ($_POST['attr'] AS $attrID => $checked) { 
      $values[] = $attrID; 
      $where_condition = "`deals`.`id`=`deal_attribute_values`.`deal_id` 
      AND `deal_attribute_values`.`deal_attribute_id`=? 
      AND `deal_attribute_values`.`value` IN ("; 
      $bind_placeholder = array(); 
      foreach($checked as $val) { 
        $bind_placeholder[] = "?"; 
        $values[] = $val; 
      } 
      $where_condition .= implode(',', $bind_placeholder).")"; 
      $where[] = $where_condition; 
     } 

Powtórz odpowiedź: Wystąpił błąd logiczny w Twoje zapytanie. Gdy wprowadzisz więcej niż jedną kategorię atrybutów, następujący warunek: deal_attribute_values.deal_attribute_id=? pojawia się dwukrotnie. Oznacza to, że deal_attribute_id musi być równy 2 wartości w tym samym czasie dla tego samego wiersza, co nie jest możliwe.

Będziesz musiał zmodyfikować zapytanie, aby dla każdej kategorii/zestawu atrybutów, które dodajesz do zapytania, musisz dodać deal_attribute_values do listy dołączania. Tak dla twojej ostatniej aktualizacji kwerendy powinien wyglądać mniej więcej tak:

SELECT deals.*, deal_categories.name AS catName FROM deals,deal_categories,deal_attribute_values, deal_attribute_values AS dav2 WHERE deals.deal_category_id=deal_categories.id AND deals.deal_category_id=? AND deals.price >= ? AND deals.price <= ? AND deals.start_date >= ? AND deals.end_date <= ? AND deals.id=deal_attribute_values.deal_id AND deal_ attribute_values.deal_attribute_id=? AND deal_attribute_values.value IN (?,?,?,?) AND deals.id=dav2.deal_id AND dav2.deal_attribute_id=? AND dav2.value IN (?,?,?)

Zauważ, że dodałem deal_attribute_values jak dav2 to w celu dostosowania 2nd grupę atrybutów też.

A dla zmiany kodu wymaganego do tego whould być podobne (patrz zmiany do $tables[] części):

 
    if (isset($_POST['attr']) && valid_array($_POST['attr'])) { 
     foreach ($_POST['attr'] AS $attrID => $checked) { 
      current_table = "`deal_attribute_values` AS dav".$attrID; 
      $values[] = $attrID; 
      $where_condition = "`deals`.`id`=`".$current_table."`.`deal_id` 
      AND `".$current_table."`.`deal_attribute_id`=? 
      AND `".$current_table."`.`value` IN ("; 
      $bind_placeholder = array(); 
      foreach($checked as $val) { 
        $bind_placeholder[] = "?"; 
        $values[] = $val; 
      } 
      $where_condition .= implode(',', $bind_placeholder).")"; 
      $where[] = $where_condition; 
      $tables[] = $current_table; 
     } 
    } 
+0

To "prawie" załatwiło sprawę! Po powrocie wyświetla odpowiednie telefony komórkowe po zaznaczeniu "Producent" i "Dostawca". Moment, w którym usuwam któregokolwiek z producentów, znika, nawet jeśli ponownie go ponowię. Jeśli odznaczę, że wszyscy dostawcy i tylko zostawiają manufaktury wszystkie zaznaczone, działa to idealnie, jednak w momencie, gdy dodaję dostawcę (nawet jeśli jest on właściwie dopasowany lub nawet tyka wszystkich dostawców), nie dostaję żadnych wyników. Jest tak silny, jakby 2 atrybuty nie mogły działać w tym samym czasie (uruchamia tylko IN() na producentach lub IN() na dostawcach. Wszelkie pomysły? – mauzilla

+0

Powinno być ok. Czy jesteś pewien, że odpowiednie wartości są powiązane do zapytania? BTW, której z dwóch opcji używasz? – AlexL

+0

Tak więc w tym przypadku kategoria (Telefony komórkowe) ma 2 atrybuty (Dostawca, Producent) .Kiedy produkt jest tworzony, atrybuty są również wybrane jako przykład Produktem może być Samsung i Vodafone jako dostawca.W moim froncie zwracam wszystkich możliwych dostawców i wszystkich możliwych producentów, i na podstawie pól wyboru powinien on filtrować i znajdować wszystkie produkty u dowolnego dostawcy i dowolnego producenta. produkt MA PRODUCENTA i dostawcę, więc jeśli użytkownik wybrał tylko Samsung jako producenta i pozostawił wszystkich dostawców sprawdzonych, powinien nadal zwracać. Czy to pomaga? – mauzilla

Powiązane problemy