那么让我们说我有一个菜单系统,所有导航项都存储在MySQL表中,如下所示:
Table: Menu
-------------------------------------------------------
| id | title | url | parent_id |
-------------------------------------------------------
| 1 | Home | /home | 0 |
| 2 | About | /about | 0 |
| 3 | History | /about/history | 2 |
| 4 | Location | /about/location | 2 |
| 5 | Staff | /about/staff | 2 |
| 6 | Articles | /blog | 0 |
| 7 | Archive | /blog/archive | 6 |
| 8 | Tags | /blog/tags | 6 |
| 9 | Tag Name 1 | /blog/tags/tag-name-1 | 8 |
| 10 | Tag Name 2 | /blog/tags/tag-name-2 | 8 |
-------------------------------------------------------
正如您所看到的,这个表非常简单,唯一的复杂因素是自引用列parent_id
,它定义了菜单应该如何嵌套。
所以这会产生以下菜单:
- Home
- About
- History
- Location
- Staff
- Articles
- Archive
- Tags
- Tag Name 1
- Tag Name 2
有没有办法从上面的表中获取这个结构而不使用PHP中的递归函数(但它可能是Python,Java或任何其他语言),每次迭代都会查询数据库?
理想情况下,这可以通过一个MySQL查询来处理。也许需要更改表结构以适应这种情况 - 如果是这样的话?
答案 0 :(得分:4)
你可以在一次拉动中拉出所有这些,然后在PHP中递归地使用它。这样可以节省一些查询时间,但可以节省一些脚本时间。
我会做这样的事情:
Get all data, ordered by parent id
Put row into $data[$parent_id][]
define function to build menu, takes one param which is id
get $data[$id] and work with that array, building the array.
while looping through the items, check if size of $data[current-item-id] > 0
if so, call above function with 0 as param
这样,您只需查询一次数据库,但可以使用更多的服务器ram。
答案 1 :(得分:2)
如果您要获取整棵树而您不能或不想更改表格结构,请查看https://stackoverflow.com/a/8325451/4833
答案 2 :(得分:1)
这可以在sql查询中完成,看看这个资源解释了查询中的递归
http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1ch20.html。
答案 3 :(得分:0)
MySQL没有默认功能来执行此操作。
您可以使用循环procedure
来获取所需的数据结果,或者在sql select中创建函数并使用。
无论如何你会使用循环。
示例:
DROP PROCEDURE IF EXISTS famsubtree;
DELIMITER go
CREATE PROCEDURE famsubtree( root INT )
BEGIN
DROP TABLE IF EXISTS famsubtree;
CREATE TABLE famsubtree
SELECT childID, parentID, 0 AS level
FROM familytree
WHERE parentID = root;
ALTER TABLE famsubtree ADD PRIMARY KEY(childID,parentID);
REPEAT
INSERT IGNORE INTO famsubtree
SELECT f.childID, f.parentID, s.level+1
FROM familytree AS f
JOIN famsubtree AS s ON f.parentID = s.childID;
UNTIL Row_Count() = 0 END REPEAT;
E ND ;
go
DELIMITER ;
并用于查询:
call famsubtree(1); -- from the root you can see forever
SELECT Concat(Space(level),parentID) AS Parent, Group_Concat(childID ORDER BY childID) AS Child
FROM famsubtree
GROUP BY parentID;