在MySQL中生成分层数据集

时间:2012-07-31 21:13:16

标签: 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

这会产生下表:

--------------------------
|  mgtuserId  |  userId  |
--------------------------
|     1       |     2    |
|     1       |     3    |
|     3       |     4    |
|     5       |     6    |
--------------------------

我希望有一个查询或存储过程,通过遵循层次结构来返回管理用户列表。因此,如果您是用户1,则将输出以下列表。

 1, 2, 3, 4 

然后,如果您是用户2,那么您将只有2个输出。

 2 

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

 5, 6 

实现这一点的最佳方法是,我有每个用户ID。

提前致谢。

3 个答案:

答案 0 :(得分:1)

替换你的桌名上的YOUR_TABLE

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

并在my.ini中设置

thread_stack = 256K

答案 1 :(得分:0)

为您提供一些搜索字词:您正在寻找关系的传递闭包,这需要递归查询。据我所知,除了在存储过程或函数的帮助下,无法在MySQL中表达recusrive查询。

a search中使用上述某些条款会为您提供与您的问题密切相关的大量问题和答案。 how to work with recursive query in MySql?就是其中之一。答案会链接到a document,其中描述的PROCEDURE recursivesubtree可能是您实施的良好起点。

答案 2 :(得分:0)

输出规格导致我的版本略有不同。

假设您没有任何“循环”,并且没有任何行,其中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级。

目前,我没有看到将其转换为您指定的结果集的好方法。

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

为了向每个叶节点提供一个未指定数量的级别,我们确实需要使用临时表,并迭代地执行相同类型的查询。但当然,这不是一个单一的查询。

(我将研究一种返回指定结果集的解决方案。)