2013-01-20 17 views
5

Mam w następstwie dwóch tabel MySQLmysql wybierz ograniczają, dołącz gdzie

  • produkty (product_id, nazwa, kategoria)
  • products_sizes (product_id, rozmiar)

każdy produkt może mieć wiele rozmiary

muszę dokonać kwerendy

  1. wybiera produkt na podstawie kategorii i rozmiaru (jeśli ustawiono rozmiar) - np. category = "buty" i rozmiar = "10"
  2. musi nadal zwracać wszystkie rozmiary produktu, ale tylko wtedy, gdy produkt ma określony rozmiar jak na rozmiarach
  3. musi jednocześnie ograniczać wyniki produktów do pewnej liczby z przesunięciem

Co mam teraz zapytanie poniżej. Pracuję, ale nie ograniczam się do kategorii i zwracam tylko jeden określony rozmiar (tutaj "10") - potrzebuję wszystkich rozmiarów, ale tylko dla produktów, które mają "10" wśród swoich rozmiarów ...

SELECT products.* 
    , products_sizes.* 
FROM (
    SELECT * 
    FROM products 
    LIMIT $limit OFFSET $offset 
    ) AS products 
LEFT JOIN products_sizes 
    ON products.products_id = products_sizes.products_id 
WHERE products_sizes.size = 10 

... a jeśli dodać GDZIE category = 'coś' kwerenda zwraca nic ...

SELECT products.* 
    , products_sizes.* 
FROM (
    SELECT * 
    FROM products 
    WHERE category = 'shoes' 
    LIMIT $limit OFFSET $offset 
    ) AS products 
LEFT JOIN products_sizes 
    ON products.products_id = products_sizes.products_id 
WHERE products_sizes.size = 10 

??

UPDATE: coraz bliżej ...

Po przeczytaniu odpowiedzi teraz mam to:

SELECT * 
FROM products AS p 
LEFT JOIN products_sizes AS s 
    ON p.product_id = s.product_id 
    WHERE s.product_id 
     IN (SELECT product_id FROM s WHERE size = 10) 
    AND p.category = 'shoes' 

To spełnia dwa pierwsze wymagania Moje pierwsze pytanie to:

  1. zwraca wyniki ograniczona kategorią i rozmiarem
  2. Zwraca wszystkie rozmiary dla każdego produktu ct, jeśli jeden z jego rozmiarów jest zgodny z podanym rozmiarem

... ALE nadal muszę ograniczyć wyniki do określonej liczby produktów. Jeśli ustawię limit LIMIT $ na samym końcu zapytania, ograniczy on liczbę zwracanych rozmiarów, a nie liczbę produktów ... Dzięki za dane wejściowe.

Odpowiedz

1

Klauzula o klauzuli WHERE w głównym pytaniu jest niezgodna z celem twojego LEFT JOIN, czyniąc go tym samym, co INNER JOIN. Bardzo możliwe, że nie ma żadnych wierszy wybranych przez dopasowywaną tabelę (buty o rozmiarze 10).

chyba że jest coś o twoich danych nie pokazano, można spróbować to:

SELECT products.* 
    , products_sizes.* 
FROM products 
JOIN products_sizes 
    ON products.products_id = products_sizes.products_id 
WHERE products.category = 'shoes' 
    AND products_sizes.size = 10 
LIMIT $limit OFFSET $offset 
-1
SELECT * 
FROM products AS p 
LEFT JOIN products_sizes AS s ON p.product_id = s.product_id 
WHERE p.product_id IN (SELECT product_id FROM products_sizes WHERE size = 10) 
LIMIT 15 

EDIT (wyjaśnienie):

Myślałam o nim i zrealizowane warto także znać uzasadnienie: p

Jesteś zainteresowany produktami , które spełniają określone kryteria, więc jest to podstawowa tabela do wyboru.

Chcesz poznać rozmiary dostępne dla tego produktu, dołączaj rozmiary do produktów.

Interesują Cię tylko produkty o określonej wielkości. Przeprowadź zapytanie podrzędne, aby znaleźć produkty o tym rozmiarze. Wyświetl tylko te produkty.

+0

daje to błąd "Podkwerenda zwraca więcej niż 1 wiersz" i wydaje się ograniczać liczbę zwracanych rozmiarów, a nie liczbę produktów. Zobacz aktualizację pytania. Nie jestem jeszcze na miejscu, ale użyłem twojego wkładu z tej odpowiedzi. Dzięki – 2083

+0

@AndreasBloch Właśnie przyjrzałem się aktualizacji. Spróbuj użyć LIMIT wewnątrz pod-zapytania. To powinno ograniczyć liczbę product_ids, które pasują do. – Dan

+0

Niestety to nie działa. Zastanawiałem się, gdzie w drugim wierszu kwerendy potrzebna jest klauzula where (intuicyjnie ma to dla mnie największy sens), więc powiedziałbym "Z produktów LIMIT $ limit AS p" - ale to również daje mi błąd – 2083

0

Twoje ostateczne zapytanie było całkowicie poprawne. Po prostu użyj limitu wewnątrz podzapytania, który będzie wiązał liczbę produktów.

+0

Niestety nie można użyć 'LIMIT' w podkwerendy IN –

0

Istnieją co najmniej trzy formaty wyników, które można użyć:

  1. Jeden rząd na wielkości, ale jest ograniczona do 10 różnych produktów
  2. 10 rzędów - jeden dla każdego produktu z kolumny zawierającej przecinkami oddzielone rozmiary
  3. dwa zestawy wyników, które można łączyć w PHP
    • 10 produktów
    • odnośne rozmiary

Dla każdego formatu potrzebujesz jakoś zwrócić 10 różnych produktów odpowiadających Twoim warunkom.

Najbardziej wyraziste sposobem jest użycie EXISTS klauzuli:

select p.* 
from products p 
where p.category = 'shoes' 
and exists (
    select * 
    from products_sizes ps 
    where ps.product_id = p.product_id 
     and ps.size = 10 
) 
order by p.product_id 
limit $limit offset $offset 

Innym sposobem jest użycie JOIN:

select p.* 
from products p 
join products_sizes ps 
    on ps.product_id = p.product_id 
where p.category = 'shoes' 
    and ps.size = 10 
order by p.product_id 
limit $limit offset $offset 

będę dalej używać drugi ze względu na swoją kompaktową kodu. Ale zawsze możesz zastąpić go instrukcją EXISTS.

1.

select p.*, ps.size 
from (
    select p.* 
    from products p 
    join products_sizes ps 
     on ps.product_id = p.product_id 
    where p.category = 'shoes' 
     and ps.size = 10 
    order by p.product_id 
    limit $limit offset $offset 
) p 
join products_sizes ps 
    on ps.product_id = p.product_id 
order by p.product_id, ps.size 

2.

select p.*, group_concat(ps.size order by ps.size) as sizes 
from products p 
join products_sizes ps1 
    on ps1.product_id = p.product_id 
join products_sizes ps 
    on ps.product_id = p.product_id 
where p.category = 'shoes' 
    and ps1.size = 10 
group by p.product_id 
order by p.product_id 
limit $limit offset $offset 

Można użyć explode() przekonwertować ciąg do tablicy w PHP:

$product->sizes = explode(',' $product->sizes); 

3.

select p.* 
from products p 
join products_sizes ps 
    on ps.product_id = p.product_id 
where p.category = 'shoes' 
    and ps.size = 10 
limit $limit offset $offset 

Zapisz wynik w tablicy indeksowanej według identyfikatora produktu. Na przykład. w fetchAssoc pętli:

$row->sizes = array(); 
$products[$row->product_id] = $row; 

Ekstrakt identyfikatory produktu od wyniku:

$productIds = (',', array_keys($products)); 

Pobiera odnośne rozmiary z;

select product_id, size 
from products_sizes 
where product_id in ($productIds) 
order by product_id, size 

link rozmiary w pętli

$products[$row->product_id]->sizes[] = $row->size; 

otrzymuje następujące dane przykładowe

| product_id | name | category | sizes | 
|------------|--------|----------|-------| 
|   1 | shoes1 | shoes | 8,9 | 
|   2 | shirt1 | shirts | 10,11 | 
|   3 | shoes2 | shoes | 9,10 | 
|   4 | shoes3 | shoes | 10,11 | 
|   5 | shoes4 | shoes | 10,12 | 

i obsługiwanie LIMIT 2 OFFSET 0, wyniki będą:

1.

| product_id | name | category | size | 
|------------|--------|----------|------| 
|   3 | shoes2 | shoes | 9 | 
|   3 | shoes2 | shoes | 10 | 
|   4 | shoes3 | shoes | 10 | 
|   4 | shoes3 | shoes | 11 | 

2.

| product_id | name | category | sizes | 
|------------|--------|----------|-------| 
|   3 | shoes2 | shoes | 9,10 | 
|   4 | shoes3 | shoes | 10,11 | 

3.

| product_id | name | category | 
|------------|--------|----------| 
|   3 | shoes2 | shoes | 
|   4 | shoes3 | shoes | 

| product_id | size | 
|------------|------| 
|   3 | 9 | 
|   3 | 10 | 
|   4 | 10 | 
|   4 | 11 | 

demo: