【问题标题】:find out list of inverted hierarchy in mysql找出mysql中的倒置层次结构列表
【发布时间】:2013-10-06 13:40:59
【问题描述】:

假设我有一个表 (Mysql myISAM) 具有子->父关系(类别和多个级别的子类别)

+--------+---------+
| id     |parent_id|
+--------+---------+
| 1      |  null   |
| 2      |    1    |
| 3      |    2    |
| 4      |    7    |
| 5      |    1    |
| 6      |    5    |
+--------+---------+

您将如何找到某个 ID 的所有孩子,例如查询 id 1 会输出: 2,5,3,6 ? (顺序不重要)

换句话说,如何在这个 parent_link 上做一个还原的子查询?

目前,我在php中循环并查询parent_id,然后在有结果时再次将所有结果连接到一个字符串中,但这太慢了......

【问题讨论】:

  • 为什么结果是 4,1,5,6 而不是 4,1,3,2,4,1,3,.... 在我看来 1 连接到 5和 3,不是吗?
  • @Gidil,抱歉,只是一些随机数据,你是对的,已修复此问题

标签: mysql sql myisam


【解决方案1】:

好的,感谢 Deepak 代码,我设法编写了这个,可读性更短,它接受一个表格作为参数并返回元素的深度。

DELIMITER $$

CREATE PROCEDURE get_children(IN V_KEY INT,IN SOURCETABLE VARCHAR(255))
proc:
BEGIN
  DECLARE vid text;
  DECLARE count int;

  DROP TABLE IF EXISTS `temp_child_nodes`;
  CREATE TEMPORARY TABLE temp_child_nodes(id int, depth int);

  SET vid = V_KEY;
  SET @val = '';
  SET count = 0;

  WHILE (vid is NOT NULL) DO 

      SET @sql = CONCAT("INSERT INTO temp_child_nodes(id,depth) SELECT id,'",count,"' from ",SOURCETABLE," where parent_id IN (",vid,")");
      PREPARE stmt1 FROM @sql;
      EXECUTE stmt1;
      DEALLOCATE PREPARE stmt1;


      SET @tsql = CONCAT("SELECT GROUP_CONCAT(id) INTO @val from ",SOURCETABLE," where parent_id IN (", vid, ")");
      PREPARE stmt2 FROM @tsql;
      EXECUTE stmt2;
      DEALLOCATE PREPARE stmt2;
      SET vid = @val;

      SET count = count + 1;
  END WHILE;

  #output data
  SELECT * from temp_child_nodes; 

END
$$

DELIMITER ;

【讨论】:

    【解决方案2】:
    create table my_table(
    id int,
    parent_id int
    );
    
    insert into my_table values
    (1,null),
    (2,1),
    (3,2),
    (4,7),
    (5,1),
    (6,5);
    

    此存储过程将为您获取任何给定 id 的所有孩子

    DELIMITER $$
    DROP PROCEDURE IF EXISTS get_children$$
    
    CREATE PROCEDURE get_children(IN V_KEY INT)
    proc:
    BEGIN
      DECLARE vid text;
    declare oid text;
      DECLARE count int;
      CREATE TEMPORARY TABLE temp_child_nodes(
          id int
        );
    
      SET vid = V_KEY;
      INSERT INTO temp_child_nodes(id) SELECT id from my_table where parent_id = vid;
      SELECT GROUP_CONCAT(concat("'",id,"'")) INTO oid from my_table where parent_id = vid;
    
      SET vid = oid;
      SET count = 0;
      SET @val = '';
      WHILE (vid is NOT NULL) DO 
    
          SET @sql = CONCAT("INSERT INTO temp_child_nodes(id) SELECT id from my_table where parent_id IN (",vid,")");
          PREPARE stmt1 FROM @sql;
          EXECUTE stmt1;
          DEALLOCATE PREPARE stmt1;
    
          SET @tsql = CONCAT("SELECT GROUP_CONCAT(id) INTO @val from my_table where parent_id IN (", vid, ")");
          PREPARE stmt2 FROM @tsql;
          EXECUTE stmt2;
          DEALLOCATE PREPARE stmt2;
          SET vid = @val;
          SET count = count + 1;
      END WHILE;
      #SELECT count;
      SELECT * from temp_child_nodes; 
      #SELECT oid;
    END
    $$
    
    DELIMITER ;
    

    调用 get_children(1);

    mysql> CALL get_children(1);
    +------+
    | id   |
    +------+
    |    2 |
    |    5 |
    |    3 |
    |    6 |
    +------+
    4 rows in set (0.22 sec)
    
    Query OK, 0 rows affected (0.22 sec)
    

    【讨论】:

    • @VincentDuprez:如果您遇到任何问题,请告诉我 :)
    • 有效!我正在尝试对其进行修改以在一次调用中获取更多信息(例如深度)并添加一个附加参数来设置表,如果成功,我将在此处发送
    【解决方案3】:

    这是您查询的 sqlfiddle 演示 http://sqlfiddle.com/#!2/ca90e/6

    如果可以有“n”个孩子,那么你需要使用存储过程

    【讨论】:

    • @VincentDuprez :请参考我的第二个答案。存储过程将为您提供任何 id 的孩子,直到任何深度
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2019-06-21
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 2021-09-29
    相关资源
    最近更新 更多