Bak*_*aya 7 mysql hierarchy recursive-query hierarchical-data
我有这种情况使用Mysql上的递归查询在一个表上找到lv 2和lv3子...
我正在使用的数据库结构:
id name parent
1 A 0
2 B 0
3 C 0
4 D 1
5 E 1
6 F 2
7 G 2
8 H 3
9 I 3
10 J 4
11 K 4
Run Code Online (Sandbox Code Playgroud)
我期望的结果,当过滤数据时,id = 1,它将产生我期待的结果.
id name parent
4 D 1
5 E 1
10 J 4
11 K 4
Run Code Online (Sandbox Code Playgroud)
我一直在寻找各地,并阅读这个http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/,但我没有找到我正在寻找的结果..
任何帮助将不胜感激, 谢谢
Man*_*ana 21
如果你想获得特定父母的所有等级孩子,那么你应该试试这个
select id,
name,
parent
from (select * from tablename
order by parent, id) tablename,
(select @pv := '1') initialisation
where find_in_set(parent, @pv) > 0
and @pv := concat(@pv, ',', id)
Run Code Online (Sandbox Code Playgroud)
在我看来,在分层表结构中查找所有子节点的关键是首先找到父节点的路径,然后使用FIND_IN_SET来查看所请求的节点是否在该路径中。向上搜索比向下搜索更容易、更高效,因为指向父级的链接已经存在于表中。
那么让我们从这样的层次结构开始:
\n1 Pets\n\xe2\x94\x9c\xe2\x94\x80 2 Dogs\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 3 Katie\n\xe2\x94\x9c\xe2\x94\x80 4 Cats\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 5 George\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 6 Pete\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 7 Alice\n\xe2\x94\x9c\xe2\x94\x80 8 Other\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 9 Rabbits\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 10 Noah\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 11 Teddy\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 12 Bella\n\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 13 Rats\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 14 Henry\nRun Code Online (Sandbox Code Playgroud)\n现在您想要查找该类别下的所有子项Other(包含该类别),那么预期结果将是:
8,9,10,11,12,13,14\nRun Code Online (Sandbox Code Playgroud)\n现在让我们看一下 Henry 的层次路径。Henry (14)的父级是Rats (13),它的父级是Other (8),最后是Pets (1)。如果我们使用 ID 为 Henry 创建一条路径,它将如下所示:
\n1,8,13,14\nRun Code Online (Sandbox Code Playgroud)\n这就是 MySQL 函数FIND_IN_SET发挥作用的地方。FIND_IN_SET您可以过滤结果,其中可以在逗号分隔列表中找到变量。在此示例中,我们正在查找类别“其他”(8) 中的所有子项,我们可以简单地使用FIND_IN_SET(8, path)。
要获取分层表的路径,我想参考我在此处的帖子中的答案MySql: ORDER BYparent and child。我们只需将破折号更改为逗号,这样我们就可以使用该FIND_IN_SET函数。
上面的示例在分层表中看起来像这样:
\n+----+--------+---------+\n| id | parent | name |\n+----+--------+---------+\n| 1 | NULL | Pets |\n| 2 | 1 | Dogs |\n| 3 | 2 | Katie |\n| 4 | 1 | Cats |\n| 5 | 4 | George |\n| 6 | 4 | Pete |\n| 7 | 4 | Alice |\n| 8 | 1 | Other |\n| 9 | 8 | Rabbits |\n| 10 | 9 | Noah |\n| 11 | 9 | Teddy |\n| 12 | 9 | Bella |\n| 13 | 8 | Rats |\n| 14 | 13 | Henry |\n+----+--------+---------+\nRun Code Online (Sandbox Code Playgroud)\n在我的方法中,我将使用一个过程,该过程将递归地调用自身,并继续在路径前面添加所请求的父级,id直到它到达NULL父级。
DELIMITER $$\nCREATE DEFINER=`root`@`localhost` PROCEDURE `PATH`(IN `input` INT, OUT `output` VARCHAR(128))\nBEGIN\n\n DECLARE _id INT;\n DECLARE _parent INT;\n DECLARE _path VARCHAR(128);\n\n SET `max_sp_recursion_depth` = 50;\n\n SELECT `id`, `parent`\n INTO _id, _parent\n FROM `database`.`table`\n WHERE `table`.`id` = `input`;\n\n IF _parent IS NULL THEN\n SET _path = _id;\n ELSE\n CALL `PATH`(_parent, _path);\n SELECT CONCAT(_path, \',\', _id) INTO _path;\n END IF;\n\n SELECT _path INTO `output`;\n\nEND $$\nDELIMITER ;\nRun Code Online (Sandbox Code Playgroud)\n我们在查询中需要这些结果SELECT,因此我们FUNCTION也需要一个包装PROCEDURE.
DELIMITER $$\nCREATE DEFINER=`root`@`localhost` FUNCTION `GETPATH`(`input` INT) RETURNS VARCHAR(128)\nBEGIN\n\n CALL `PATH`(`input`, @path);\n RETURN @path;\n\nEND $$\nDELIMITER ;\nRun Code Online (Sandbox Code Playgroud)\n现在我们可以在查询中使用该路径。在我的工作站上,对于 10000 行的表,只需要一秒多一点的时间。
\nSELECT `id`, `parent`, `name`, GETPATH(`id`) `path` FROM `database`.`table`;\nRun Code Online (Sandbox Code Playgroud)\n输出示例:
\n+----+--------+---------+-----------+\n| id | parent | name | path |\n+----+--------+---------+-----------+\n| 1 | NULL | Pets | 1 |\n| 2 | 1 | Dogs | 1,2 |\n| 3 | 2 | Katie | 1,2,3 |\n| 4 | 1 | Cats | 1,4 |\n| 5 | 4 | George | 1,4,5 |\n| 6 | 4 | Pete | 1,4,6 |\n| 7 | 4 | Alice | 1,4,7 |\n| 8 | 1 | Other | 1,8 |\n| 9 | 8 | Rabbits | 1,8,9 |\n| 10 | 9 | Noah | 1,8,9,10 |\n| 11 | 9 | Teddy | 1,8,9,11 |\n| 12 | 9 | Bella | 1,8,9,12 |\n| 13 | 8 | Rats | 1,8,13 |\n| 14 | 13 | Henry | 1,8,13,14 |\n+----+--------+---------+-----------+\nRun Code Online (Sandbox Code Playgroud)\n要查找 Other (8) 的所有子级(还包括 Other 本身),我们可以使用相同的查询和过滤器FIND_IN_SET:
SELECT `id`, `parent`, `name`, GETPATH(`id`) `path` FROM `database`.`table` WHERE FIND_IN_SET(8, GETPATH(`id`));\nRun Code Online (Sandbox Code Playgroud)\n最后是结果。我们在程序中将递归限制为 50 级,但除此之外我们对深度没有限制。
\n+----+--------+---------+-----------+\n| id | parent | name | path |\n+----+--------+---------+-----------+\n| 8 | 1 | Other | 1,8 |\n| 9 | 8 | Rabbits | 1,8,9 |\n| 10 | 9 | Noah | 1,8,9,10 |\n| 11 | 9 | Teddy | 1,8,9,11 |\n| 12 | 9 | Bella | 1,8,9,12 |\n| 13 | 8 | Rats | 1,8,13 |\n| 14 | 13 | Henry | 1,8,13,14 |\n+----+--------+---------+-----------+\n7 rows in set (0,01 sec)\nRun Code Online (Sandbox Code Playgroud)\n如果您想要单个值而不是行,那么您可能需要使用GROUP_CONCAT像这样使用:
SELECT GROUP_CONCAT(`id`) `children` FROM `database`.`table` WHERE FIND_IN_SET(8, GETPATH(`id`));\nRun Code Online (Sandbox Code Playgroud)\n给你以下结果:
\n+--------------------+\n| children |\n+--------------------+\n| 8,9,10,11,12,13,14 |\n+--------------------+\n1 row in set (0,00 sec)\nRun Code Online (Sandbox Code Playgroud)\n
oll*_*law -10
SELECT *
FROM TABLENAME
WHERE PARENT = 1
UNION
SELECT *
FROM TABLENAME
WHERE PARENT IN
(SELECT ID FROM TABLENAME WHERE PARENT = 1)
Run Code Online (Sandbox Code Playgroud)