MySQL:选择类别,子类别和品牌。只有它们存在

时间:2015-02-25 17:24:41

标签: php mysql join

我有三张桌子:

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

加上产品表

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

我需要构建一个三级菜单,我很难在不查询数据库的情况下这么做。 基本上菜单就像这样

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 个答案:

答案 0 :(得分: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 />';
}

*编辑:使用嵌套的ul / li(未测试)

$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>';

答案 1 :(得分: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

等。如果您确实需要树形视图,可以使用其他选项对其进行格式化,但是您应该能够将结果打包成一个漂亮的数据结构。