2015-02-25 2 views
0

У меня есть три таблицы:MySQL: выберите категории, подкатегории и бренды. Только если они существуют

brands(id, name) 
categories(id, name) 
subcategories(id, category_id, name) 

плюс таблица продуктов

products(id, category_id, subcategory_id, brand_id, [...]) 

Мне нужно построить меню на три уровня, и я с трудом делает это без запрашивая DB слишком много раз. В основном меню, как этот

Electronics -> Smartphones -> Samsung 

Моя трудность создания дерева, как показано выше. Я не могу иметь, например, Electronics -> Smartphones -> Nike(I have Nike as a brand, but in this category/subcategory combo Nike is obviously not needed).

До сих пор я заканчивал циклы внутри петель, чтобы получать только бренды, которые существуют для каждой комбо, но это значительно увеличивает время загрузки.

Есть ли более эффективный способ сделать это?

В конце концов, я хотел бы иметь что-то вроде следующего

Electronics 
    Smartphones 
     Samsung 
     Apple 
    TVs 
     Samsung 
     Lg 
Shoes 
    Sneakers 
     Nike 
     Converse 
... 

ответ

2

Выбор на основе продуктов таблицы (не иметь пустую категорию/подкатегорию или бренд)
Сгруппированные по брендам и подкатегории (нет необходимости иметь несколько строк с тем же «комбо», как мы не нужны данные продукты для здесь отображается)
Упорядоченный в алфавитном порядке (сделать как вы хотите здесь)

$sql = 'SELECT b.id AS brand_id, b.name AS brand_name, sc.id AS subcategory_id, sc.name AS subcategory_name, c.id AS category_id, c.name AS category_name 
FROM products p 
INNER JOIN brand b ON p.brand_id = b.id 
INNER JOIN subcategory sc ON p.subcategory_id = sc.id 
INNER JOIN category c ON sc.category_id = c.id 
GROUP BY p.brand_id, p.subcategory_id 
ORDER BY c.name ASC, sc.name ASC, b.name ASC'; 

Тогда в PHP:

$lastCategoryId = 0; 
$lastSubCategoryId = 0; 

// Fetch results 
while($result = // Fetch row) { 
    if ($result->category_id != $lastCategoryId) { 
    // This is the first time you see that category: display its name (and create a ul tag for example) 
     echo '<br />'.$result->category_name.'<br />'; 
     $lastCategoryId = $result->category_id; 
    } 
    if ($result->subcategory_id != $lastSubCategoryId) { 
    // This is the first time you see that subcategory: display its name (and create a sub-ul tag for example) 
     echo '---'.$result->subcategory_name.'<br />'; 
     $lastSubCategoryId = $result->subcategory_id; 
    } 

    // No need to check the last brand_id because in the SQL we can't have the same subcategory/brand twice, so it will always be a new brand for this subcategory. 
    echo '------'.$result->brand_name.'<br />'; 
} 

* Edit: С вложенной уль/li (не TESTE d)

$lastCategoryId = 0; 
$lastSubCategoryId = 0; 

// Main list 
echo '<ul>'; 

while($result = // Fetch row) { 

    // Category level 
    if ($result->category_id != $lastCategoryId) { 
    // First time you see that category 
     // Re-init subcategory last id (so that later we can know if it's the first subcategory in this category or not) 
     $lastSubCategoryId = 0; 

     // Close previous category li (if $lastCategoryId == 0, means that there is no category to close, it's our very fist) 
     if ($lastCategoryId != 0) { 
      echo '</ul></li>'; 
     } 

     // Open li element (which will contain category name + list of subcategories) 
     echo '<li>'; 
     echo $result->category_name; 

     // Open sub-ul (which will contain subcategories list) 
     echo '<ul>'; 
    } 

    // Subcategory level 
    if ($result->subcategory_id != $lastSubCategoryId) { 
    // First time you see that subcategory 
     // Close previous subcategory li (if $lastSubCategoryId == 0, means that there is no subcategory to close, it's our first one in that category) 
     if ($lastSubCategoryId != 0) { 
      echo '</ul></li>'; 
     } 

     // Open li element (which will contain subcategory name + list of brands) 
     echo '<li>'; 
     echo $result->subcategory_name; 

     // Open sub-sub-ul (which will contain brands list) 
     echo '<ul>'; 
    } 

    echo '<li>'.$result->brand_name.'</li>'; 
} 

// Close last subcategory 
echo '</ul></li>'; 

// Close last category 
echo '</ul></li>'; 

// Closing main list 
echo '</ul>'; 
+0

Это отлично работает, я должен изучить его лучше, чтобы понять его, но это все. Единственное, во втором if() это $ result-> subcategory_name не $ result-> category_name. Большое спасибо! –

+0

Правильно, я отредактировал свое сообщение, чтобы исправить строку 'subcategory_name'. Возможно, вы захотите выполнить SQL-запрос в средстве phpMyAdmin (или аналогичном), чтобы увидеть результат, тогда вы лучше поймете код PHP. –

+0

В качестве последующего вопроса, как вы собираетесь делать вложенные ul/li из вашего опубликованного кода? Я немного борюсь. –

1

Довольно уверенный запрос с внутренней присоединиться все, что вам нужно, если у вас есть какой-то способ отображения бренда нескольких категорий/подкатегорий ,

select c.name, sc.name, b.name 
from brands b 
inner join subcategories sc where sc.id = b.subcategory_id 
inner join categories c where c.id = b.category_id 

Это будет строить результаты, как

Electronics Smartphones Samsung 
Electronics Smartphones Apple 
... 
Shoes   Sneakers  Nike 

и т.д. Если вам действительно нужно, что вид дерева в стиле, есть и другие варианты, которые можно использовать для форматирования, но вы должны быть в состоянии упаковать приводит к хорошей структуре данных.

Смежные вопросы