在MySQL中生成分层数据集

在MySQL中生成分层数据集,mysql,Mysql,我有一个用户ID值表,a列有管理用户,B列有用户。例如,我希望能够显示管理其他用户的用户列表 User 1 can manage user 2 User 1 can manage user 3 User 3 can manage user 4 User 5 can manage user 6 用户1可以管理用户2 用户1可以管理用户3 用户3可以管理用户4 用户5可以管理用户6 这将生成下表: -------------------------- | mgtuserId | userId

我有一个用户ID值表,a列有管理用户,B列有用户。例如,我希望能够显示管理其他用户的用户列表

User 1 can manage user 2 User 1 can manage user 3 User 3 can manage user 4 User 5 can manage user 6 用户1可以管理用户2 用户1可以管理用户3 用户3可以管理用户4 用户5可以管理用户6 这将生成下表:

-------------------------- | mgtuserId | userId | -------------------------- | 1 | 2 | | 1 | 3 | | 3 | 4 | | 5 | 6 | -------------------------- -------------------------- |mgtuserId | userId| -------------------------- | 1 | 2 | | 1 | 3 | | 3 | 4 | | 5 | 6 | -------------------------- 我希望有一个查询或存储过程,通过跟踪层次结构返回管理用户列表。因此,如果您是用户1,将输出以下列表

1, 2, 3, 4 1, 2, 3, 4 如果您是用户2,那么您将只有2个输出

2 2. 然后,如果您是用户5,则输出以下列表,依此类推

5, 6 5, 6 如果我有每个用户的Id,那么实现这一点的最佳方法是什么


提前感谢。

给您一些搜索词:您正在寻找关系的传递闭包,这需要递归查询。据我所知,递归查询不能在MySQL中表达,除非借助存储过程或函数


在中使用上述一些术语会给你大量与你的问题密切相关的问题和答案。是其中之一。这里的答案链接描述了一个
过程递归子树
,它可能是实现的良好起点。

您的输出规范导致了与我所做的略有不同的版本

假设没有任何“循环”,也没有mgtuserId=userId的行,则可以通过多次将表连接到自身来模拟N个级别的分层查询,如下所示:

SELECT n0.userId AS n0_userId
     , n1.userId AS n1_userId
     , n2.userId AS n2_userId
     , n3.userId AS n3_userId
     , n4.userId AS n4_userId
     , n5.userId AS n5_userId
     , n6.userId AS n6_userId
  FROM mytable n0
  LEFT JOIN mytable n1 ON n1.mgtuserId = n0.userId
  LEFT JOIN mytable n2 ON n2.mgtuserId = n1.userId
  LEFT JOIN mytable n3 ON n3.mgtuserId = n2.userId
  LEFT JOIN mytable n4 ON n4.mgtuserId = n3.userId
  LEFT JOIN mytable n5 ON n5.mgtuserId = n4.userId
  LEFT JOIN mytable n6 ON n6.mgtuserId = n5.userId
 WHERE n0.userId = 1
但此查询不会返回您指定的结果集,即逗号分隔的列表

此查询返回的每一行表示树下的一条“路径”,从指定的起点到每个叶节点(或者,在本例中,到每个深度不超过六层(低于指定的起点)的节点)

不,这并不漂亮。但是你可以看到它是如何扩展到N个级别的

现在,我看不到一个好方法可以将其转换为您指定的结果集

我可能不得不做同样的事情,但是用一个单独的查询(一个级别深,两个级别深,等等)获取每个级别,然后使用一个联合来组合它们。但是这将更加丑陋

要获得每个叶节点的未指定级别数,我们确实需要使用一个临时表,并以迭代方式执行相同类型的查询


(我将处理一个返回指定结果集的解决方案。)

替换表名上的_表

DELIMITER $$

CREATE PROCEDURE get_users(IN base INT UNSIGNED)
BEGIN
DECLARE ids TEXT DEFAULT '';

SET @parents = base;
SET ids = base;

loop1: LOOP
    SET @stm = CONCAT(
        'SELECT GROUP_CONCAT(userId) INTO @parents FROM YOUR_TABLE',
        ' WHERE mgtuserId IN (', @parents, ')'
    );

    PREPARE fetch_childs FROM @stm;
    EXECUTE fetch_childs;
    DROP PREPARE fetch_childs;

    IF @parents IS NULL THEN LEAVE loop1; END IF;

    SET ids = CONCAT(ids, ',', @parents);
END LOOP;

SET @stm = CONCAT('(SELECT mgtuserId FROM YOUR_TABLE WHERE mgtuserId=',base,') UNION (SELECT userId FROM YOUR_TABLE WHERE userId IN (',ids, '))');

PREPARE fetch_childs FROM @stm;
EXECUTE fetch_childs;
DROP PREPARE fetch_childs;
END;
检查

CALL get_users(1);
1
2
3
4
并设置在我的.ini中

thread_stack = 256K