我想从仅使用MySQL的树中获取孩子们的所有ID。
我有一张这样的表:
ID parent_id name
1 0 cat1
2 1 subcat1
3 2 sub-subcat1
4 2 sub-subcat2
5 0 cat2
现在我试图以递归方式获取cat1(2,3,4)的所有子ID。有什么办法可以实现吗?
答案 0 :(得分:15)
执行此操作有两种基本方法:邻接列表和嵌套列表。看看Managing Hierarchical Data in MySQL。
你所拥有的是一份邻接名单。没有办法用一个SQL语句递归抓取所有后代。如果可能,只需抓住它们并将它们全部映射到代码中。
嵌套集可以做你想要的,但我倾向于避免它,因为插入记录的成本很高而且容易出错。
答案 1 :(得分:7)
这是一个简单的单查询MySql-solution:
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
只需将<id>
替换为父元素&#39; s ID
。
这将返回一个字符串,其中包含ID
= ID
元素的所有后代的<id>
个,由,
分隔。如果您希望返回多行,每行有一个后代,则可以使用以下内容:
SELECT *
FROM `table_name`
WHERE FIND_IN_SET(`ID`, (
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
))
包含root / parent元素
OP询问了一个元素的孩子,上面已经回答了这个问题。在某些情况下,在结果中包含root / parent元素可能很有用。以下是我建议的解决方案:
以逗号分隔的ID字符串:
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT <id> Level
UNION
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
多行:
SELECT *
FROM `table_name`
WHERE `ID` = <id> OR FIND_IN_SET(`ID`, (
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
))
答案 2 :(得分:1)
你可以用存储过程来完成它,如果这是你的选择。
否则你不能用一个sql语句来做。
理想情况下,您应该进行递归调用以从程序中移动树
答案 3 :(得分:1)
创建表格应该如下所示
DROP TABLE IF EXISTS `parent_child`;
CREATE TABLE `parent_child` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
insert into `parent_child`(`id`,`name`,`parent_id`)
values (1,'cat1',0),(2,'subcat1',1),
(3,'sub-subcat1',2),(4,'sub-subcat2',2),
(5,'cat2',0);
创建获取父子元素的函数
DELIMITER $$
USE `yourdatabase`$$
DROP FUNCTION IF EXISTS `GetAllNode1`$$
CREATE DEFINER=`root`@`localhost` FUNCTION `GetAllNode1`(GivenID INT) RETURNS TEXT CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE rv,q,queue,queue_children TEXT;
DECLARE queue_length,front_id,pos INT;
SET rv = '';
SET queue = GivenID;
SET queue_length = 1;
WHILE queue_length > 0 DO
SET front_id = queue;
IF queue_length = 1 THEN
SET queue = '';
ELSE
SET pos = LOCATE(',',queue) + 1;
SET q = SUBSTR(queue,pos);
SET queue = q;
END IF;
SET queue_length = queue_length - 1;
SELECT IFNULL(qc,'') INTO queue_children
FROM (SELECT GROUP_CONCAT(id) AS qc
FROM `parent_child` WHERE `parent_id` = front_id) A ;
IF LENGTH(queue_children) = 0 THEN
IF LENGTH(queue) = 0 THEN
SET queue_length = 0;
END IF;
ELSE
IF LENGTH(rv) = 0 THEN
SET rv = queue_children;
ELSE
SET rv = CONCAT(rv,',',queue_children);
END IF;
IF LENGTH(queue) = 0 THEN
SET queue = queue_children;
ELSE
SET queue = CONCAT(queue,',',queue_children);
END IF;
SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1;
END IF;
END WHILE;
RETURN rv;
END$$
DELIMITER ;
为欲望输出编写查询
SELECT GetAllNode1(id) FROM parent_child
or
SELECT GetAllNode1(id) FROM parent_child where id =1 //for specific parent's child element
答案 4 :(得分:0)
通过单个MYSQL语句看到答案基本上没有或至少不是很容易,我将发布我的php / mysql代码来执行层次结构列表..
function createCategorySubArray()
{
$categories = getSQL("SELECT pos_category_id FROM pos_categories");
for($i=0;$i<sizeof($categories);$i++)
{
//here we need to find all sub categories
$pos_category_id = $categories[$i]['pos_category_id'];
$cat_list[$pos_category_id] = recursiveCategory($pos_category_id,array());
}
return $cat_list;
}
function recursiveCategory($pos_category_id, $array)
{
$return = getSql("SELECT pos_category_id FROM pos_categories WHERE parent = $pos_category_id");
for($i=0;$i<sizeof($return);$i++)
{
$sub_cat = $return[$i]['pos_category_id'];
$array[] = $sub_cat;
$array = recursiveCategory($sub_cat, $array);
}
return $array;
}
然后你叫它 $ cat_array = createCategorySubArray();
我需要这样才能找出基于产品类别的促销活动正在应用于子类别。
答案 5 :(得分:-1)
你的问题似乎有点不精确。你为什么要拥有它们,拥有它们是什么意思,“在树上”?
你得到的表是IS(表示关系的方式)树。
如果你希望它们“在一个表中”包含保存对的行(ID 4,ParentID 0),那么你需要你的SQL引擎版本的递归SQL来执行此操作,如果该引擎支持它。
我不会特别了解MySQL,但我的理解是他们曾经计划使用与Oracle相同的语法实现递归SQL,即使用CONNECT BY。
如果您在手册的目录中查找“递归查询”或“连接点”等关键字,我想您应该能够找到答案。
(很抱歉无法提供更准备好的答案。)