如何通过选择顶级类别来检索属于子类别的项目?

时间:2011-05-12 15:10:36

标签: php mysql

请参阅下面的数据表和查询..

Items
Id, Name
1, Item 1
2, Item 2

Categories
Id, Name, Parent ID
1, Furniture , 0
2, Tables, 1
3, Beds, 1
4, Dining Table, 2
5, Bar Table, 2
4, Electronics, 0
5, Home, 4
6, Outdoors, 4
7, Table lamp, 4

ItemCategory
ItemId, CategoryId
1, 2 .. Row1
2, 4 .. Row 2
2, 5 .. Row 3 

ItemCategory表存储哪些项属于哪个类别。项目可以属于顶级和/或子类别。大约有3个级别的深层类别,即Tob级别,子级别和子级别。

用户选择他们想要查看和提交的所有类别,我可以使用下面的示例查询查询数据库。

    SELECT * FROM items i INNER JOIN ItemCategory ic ON 
ic.itemId = i.itemId AND ic.itemId IN ('comma separated category ids')

这很好用。

我的问题是,是否可以查看顶级类别下的所有项目,即使它尚未直接分配给该项目。例如,如果用户选择上面的家具,那么它会列出属于其子类别的所有项目(即使ItemCategory不包含任何记录)?

我愿意对数据表或查询进行必要的修改,请提出解决方案。谢谢。

3 个答案:

答案 0 :(得分:1)

通过递归,一切皆有可能:

function fetchItemsByCat($cat, &$results) {
    $itemsInCat = query("SELECT Items.Id FROM Items INNER JOIN ItemCategory ON ItemCategory.ItemId = Items.Id WHERE CategoryId = ?", array($cat));

    while($row = *_fetch_array($itemsInCat)) 
        array_push($results, $row['Id']);

    $subCategories = query("SELECT Id FROM Categories WHERE Parent = ?", array( $cat ));
    while($row = *_fetch_array($subCategories))
        $results = fetchItemsByCat($row['Id'], $results);

    return $results;
}

$startCat = 1;  // Furniture

$itemsInCat = fetchItemsByCat($startCat, array());

该函数有点伪代码。将*_fetch_array替换为您正在使用的数据库扩展。但是查询功能是您正在查询数据库。

此外,这是未经测试的,因此您应该测试由于使用数组引用而导致的意外结果,尽管我认为这样做很好。

调用函数后,$itemsInCat将是给定开始类别中存在的所有项/子项的整数id的数组。如果你想得到想象,你可以返回一个数组数组,每个第二级数组元素都有一个项目ID,以及该项目分配的类别ID,项目名称等。

答案 1 :(得分:1)

Watcher已经给出了一个很好的答案,但是我在某种程度上改变了我的方法,所以你有一个结构化的递归二维数组,其中类别为键,项目为值。这使得在响应搜索要求时可以非常轻松地打印回用户。

这是我的方法,我测试过:

$items = getItemsByCategory($topCategory);
//To print contents
print_r($items);

function getItemsByCategory($sid = 0) {
  $list = array();
  $sql = "SELECT Id, Name FROM Categories WHERE ParentId = $sid";
  $rs = mysql_query($sql);
  while ($obj = mysql_fetch_object($rs)) {
    //echo $obj->id .", ".$parent." >> ".$obj->name."<br/>";
    $list[$obj->name] = getItems($obj->id);
    if (hasChildren($obj->id)) {
        array_push($list[$obj->name],getItemsByCategory($obj->id));
    }
  }
  return $list;
}

function getItems($cid) {
  $list = array();
  $sql = "SELECT i.Id, i.Name FROM Items p INNER JOIN ItemCategory ic ON i.id = ic.ItemId WHERE ic.CategoryId = $cid";
  $rs = mysql_query($sql);
  while ($obj = mysql_fetch_object($rs)) {
    $list[] = array($obj->id, $obj->name);
  }
  return $list;
}

function hasChildren($pid) {
  $sql = "SELECT * FROM Categories WHERE ParentId = $pid";
  $rs = mysql_query($sql);
  if (mysql_num_rows($rs) > 0) {
    return true;
  } else {
    return false;
  }
}

希望这有帮助。

答案 2 :(得分:0)

如果您使用MySQL,那么使用典型技术索引您的树是不吉利的,这通常意味着预先计算和存储路径,或者使用嵌套集:

http://en.wikipedia.org/wiki/Nested_set_model

如果您可以切换到PostgreSQL,您也可以使用递归查询:

http://www.postgresql.org/docs/9.0/static/queries-with.html

显然,您也可以从您的应用程序递归查询,但效率低得多。

相关问题