如何在MySQL和PHP中使用嵌套集获取结构化结果?

11
5个回答

5

我不确定这是否完全符合您的要求,但值得注意的是,在MySQL中,您可以通过使用GROUP_CONCAT并扩展http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/中的“检索单个路径”示例,获取整个树形结构,每条路径作为一个字符串,每行一条。

SELECT 
  GROUP_CONCAT(parent.name ORDER BY parent.lft ASC SEPARATOR '|') 
FROM nested_category AS node
     CROSS JOIN nested_category AS parent 
WHERE 
  node.lft BETWEEN parent.lft AND parent.rgt 
GROUP by node.id 
ORDER BY node.lft;

这将输出树中每个节点的路径。

注意,nested_category AS node CROSS JOIN nested_category AS parent 等同于 nested_category AS node, nested_category AS parent

如果您想将其展开为路径元素数组并且知道存在不在数据中的字符串,则可以指定该字符串作为分隔符,本示例使用 '|' 作为分隔符。


使用此解决方案,您可以在foreach()内部使用格式良好的eval()快速解析为嵌套数组,仅需2行代码。从安全角度考虑,这假定类别数据是完全可信的。 - JoshuaDavid

2
我使用了类似但不完全相同的方法,也在子节点中保留了对父节点的引用; 这使从数据构建树形结构更容易。如果有用的话,我可以在PHP中发布提取数据到树形结构的代码。
@Marc,所描述的数据结构并不一定用于执行集合操作;它只是使操作该结构更容易。如果您想获取整个数据树,并且每个记录仅存储对父记录的指针,则需要递归地查询数据库以获取完整的数据树。如果使用上述方法,则可以在一个查询中提取整个集合。
编辑:这里是构建树形结构的代码,如果您仍然保留了子->父引用以及lft / right信息。我更喜欢这样做,因为这样做实际上仍然更快,如果您只想获取单个级别的直接后代,则可以使用此方法。
我试图将其简化以演示必要内容,因此可能会有一些错别字等问题,但您应该能够理解。关键部分包括:
- 按“lft ASC”排序您的查询,这样您将始终在处理其子节点之前处理父节点。 - 通过ID存储对每个节点的引用;这样,该节点的任何子代都可以轻松地找到它并将自身添加到父级中。 - 遍历结果,按ID存储每个节点的引用(如上所述),并将此节点添加到其父节点的子级中。
无论如何,以下是代码 -
<?php
$children = mysql_query('SELECT * FROM nested_category ORDER BY lft ASC');

/* Get the first child; because the query was ordered by lft ASC, this is
   the "root" of the tree */
$child          = mysql_fetch_object($children);
$root           = new StdClass;
$root->id       = $child->folderID;
$root->children = array();
/* Store a reference to the object by the id, so that children can add
   themselves to it when we come across them */
$objects        = array($root->id => $root);

/* Build a tree structure */
while ($child = mysql_fetch_object($children)) {
    /* Create a new wrapper for the data */
    $obj           = new StdClass;
    $obj->id       = $child->id;
    $obj->children = array();
    /* Append the child to the parent children */
    $parent = $objects[$child->parent];
    $parent->children[] = $obj;
    $objects[$obj->id] = $obj;
}   

此外,这个链接(http://articles.sitepoint.com/article/hierarchical-data-database/2)更易于理解,但描述了完全相同的技术。 - El Yobo

0
即使MySQL端的数据结构有些奇特,仍然可以使用正常的查询方法检索数据。发出适当的select语句,循环遍历结果,并将其填充到PHP数组中。虽然我不知道为什么你想这样做,因为在PHP中执行集合操作比在MySQL中更困难。

0

看了你的链接,我会使用左连接来实现。可以参考检索完整树的示例。

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4 FROM category AS t1 LEFT JOIN category AS t2 ON t2.parent = t1.category_id LEFT JOIN category AS t3 ON t3.parent = t2.category_id LEFT JOIN category AS t4 ON t4.parent = t3.category_id WHERE t1.name = 'ELECTRONICS';

如果要包含每个层级,您需要为每个层级使用一个左连接。 然后,可以通过 PHP 将结果解析为任何所需的数据结构。只需忽略 NULL 结果即可。

| ELECTRONICS | TELEVISIONS | TUBE | NULL |

| ELECTRONICS | TELEVISIONS | LCD | NULL |

| ELECTRONICS | TELEVISIONS | PLASMA | NULL |

| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |

| 电子产品 | 便携式电子产品 | CD播放器 | NULL |

| 电子产品 | 便携式电子产品 | 双向无线电 | NULL |

当您有一个深层结构时,这将是一种更糟糕的方法,因为MySQL连接需要很长时间来执行,当需要连接许多表时。

我希望我没有误解您的问题。


本文中所介绍的技术的整个重点在于避免使用左连接/多个查询。问题不在于查询(采用所描述的方法,你只需要“SELECT * FROM nested_category ORDER BY lft ASC”),而在于如何将查询结果转换为结构。 - El Yobo
好的,在这种情况下请忽略我的帖子。抱歉。 - cb0

0

我必须告诉你一种使用PHP处理树形结构的方法,而不需要使用递归。我认为你非常熟悉标准PHP库(SPL)。你可以使用迭代器来解决你的问题。

http://www.php.net/~helly/php/ext/spl/

这里是 SPL 文档的链接。以下是针对你上面提到的 Mysql 链接的一些解决方案:通过从表中检索数组,您可以对它们进行操作并按照您的喜好显示。

对于:邻接列表模型

您可以使用“RecursiveIteratorIterator”,它将显示所有结果,包括所有子项。

如果您只想显示子项,则可以使用“ParentIterator”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接