在MySQL表中选择树路径

时间:2017-05-28 22:32:26

标签: mysql recursion tree hierarchical

我有一个像这样的MySQL表:

| CategoryId |          Name | CategoryParentId |
|------------|---------------|------------------|
|          0 |  Tech Support |           (null) |
|          1 | Configuration |                0 |
|          2 |     Questions |                1 |
|          3 |         Sales |           (null) |
|          4 |     Questions |                3 |
|          5 |         Other |           (null) |

这是我在查询ID 2时所需的输出(例如):

技术支持/配置/问题

如何在不进行多次连接的情况下执行此操作?

Fiddle

编辑:不确定这是否是最好的方法,但我通过创建一个函数来解决:

DELIMITER $$

CREATE FUNCTION get_full_tree (CategoryId int) RETURNS VARCHAR(200)

BEGIN
SET @CategoryParentId = (SELECT CategoryParentId FROM category c WHERE c.CategoryId = CategoryId);
SET @Tree = (SELECT Name FROM category c WHERE c.CategoryId = CategoryId);
WHILE (@CategoryParentId IS NOT NULL) DO
    SET @ParentName = (SELECT Name FROM category c WHERE c.CategoryId = @CategoryParentId);
    SET @Tree = CONCAT(@ParentName, '/', @Tree);
    SET @CategoryParentId = (SELECT CategoryParentId FROM category c WHERE c.CategoryId = @CategoryParentId);
END WHILE;
RETURN @Tree;
END $$
DELIMITER ;

我现在可以执行此查询:

SELECT CategoryId, get_full_tree(CategoryId) FROM category

2 个答案:

答案 0 :(得分:1)

您可以创建一个新表,让我们将其命名为hierarchy(可能是一个更好的名称),我们将存储所有类别的祖先。

CREATE TABLE `hierarchy` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `parent` int(11) NOT NULL,
  `child` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

例如,在这种情况下Questions,即 ID-> 2 ,我们将提供以下条目:

id  parent     child
====================            
6     0         2
7     1         2
8     2         2

对于整个示例,表格的内容为:

id       parent     child
===========================
1           0           0
2           3           3
3           5           5
4           0           1
5           1           1
6           0           2
7           1           2
8           2           2
9           3           4
10          4           4

现在,只要您想要检索节点的整个祖先,就执行以下查询:

select name from category where id in (select parent from hierarchy where child = 2 order by id ASC)

以上查询将返回Questions(ID-> 2)的所有祖先名称,即

name
==================
Tech Support
Configuration
Questions

对于完整性,下面是category

的内容
id             Name
============================
0             Tech Support
1             Configuration
2             Questions
3             Sales
4             Questions
5             Other

N.B。这只是一个想法,我相信你绝对可以在它上面构建更优雅的解决方案。

答案 1 :(得分:1)

如果您使用的是MySQL 8或更高版本,则可以使用Common Table Expressions进行递归查询。查询如下

WITH RECURSIVE CategoryPath (CategoryId, Name, path) AS
(
  SELECT CategoryId, Name, Name as path
    FROM category
    WHERE CategoryParentId IS NULL
  UNION ALL
  SELECT c.CategoryId, c.Name, CONCAT(cp.path, ' / ', c.Name)
    FROM CategoryPath AS cp JOIN category AS c
      ON cp.CategoryId = c.CategoryParentId 
)
SELECT * FROM CategoryPath ORDER BY path;