树格式或添加级别的MYSQL输出(父子)

树格式或添加级别的MYSQL输出(父子),mysql,sql,tree,format,parent-child,Mysql,Sql,Tree,Format,Parent Child,下面是我桌上的东西 我的桌子 什么,我想要的是如下使用MYSQL C1 G1 G2 G3 D1 D2 G4 D3 D4 C2 G5 G6 G7 G8 请让我知道这在MYSQL中是否可行。输出类似于树 更新1 如果我得到下面这样的新表,也可以使用。 ++++++++++++++++++++++++++++++++++++++++ Parent + Child + PLevel + CLevel ++++++++++++

下面是我桌上的东西

我的桌子 什么,我想要的是如下使用MYSQL

C1
  G1
  G2
  G3
    D1
    D2
  G4
    D3
    D4

C2
  G5
  G6
  G7
  G8
请让我知道这在MYSQL中是否可行。输出类似于树

更新1 如果我得到下面这样的新表,也可以使用。

++++++++++++++++++++++++++++++++++++++++
Parent   +  Child   + PLevel  + CLevel
++++++++++++++++++++++++++++++++++++++++
  C1     +    G1    +   1    +   2
  C1     +    G2    +   1    +   2
  C1     +    G3    +   1    +   2
  G3     +    D1    +   2    +   3
  G3     +    D2    +   2    +   3
  C1     +    G4    +   1    +   2
  G4     +    D3    +   2    +   3
  G4     +    D4    +   2    +   3
  C2     +    G5    +   1    +   2
  C2     +    G6    +   1    +   2
  C2     +    G7    +   1    +   2
  C2     +    G8    +   1    +   2
++++++++++++++++++++++++++++++++++++++++

注意:我的级别从1开始(在示例中,我的级别从0开始)。如果我得到这个级别从0开始的新表,也可以。MySQL和RDBMS通常不适合这种结构。您可能必须使用客户端递归来实现这一点


如果递归仅限于三个深度,如您的示例所示,则可以使用联接进行递归,但对于较深的树来说,它的可伸缩性不是很强。

虽然不能使用单个查询,但可以使用存储过程。。。唯一的先决条件是,您需要在现有的示例表中再添加2条记录,以表示“C1”和“C2”是顶层。。。添加一条记录,其中“父级”字段为空,子级为“C1”,另一个为“C2”。这将“准备”最顶层的父级。对于后续层次关联,否则您没有顶级层次的起始“基础”。它还需要一个“主键”列(我在这个脚本中创建了一个“IDMyTable”,它只是1-x顺序的,但是假设您的表上有一个自动递增列来代替它)

我已经包含了所有的输出列来显示它是如何构建的,但是这个例程的前提是基于预期的列输出创建一个表,但是在构建过程中额外保留了下游的层次表示。为了确保它们在层变深时保持正确的方向,我将在“ID”列中添加内容——您将看到它在最终结果集中是如何工作的

然后,在最终的结果集中,我根据层次结构数据的深度预先填充空间

循环将根据在前面的结果集中找到的父记录添加任何记录,但前提是尚未添加ID(防止重复)

要查看循环顺序是如何不断追加的,您可以运行最后一个查询,而不使用ORDERBY,并查看每个迭代是如何限定和添加上一个层次结构级别的

-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetHierarchy2`()
BEGIN
    -- prepare a hierarchy level variable 
    set @hierlvl := 00000;

    -- prepare a variable for total rows so we know when no more rows found
    set @lastRowCount := 0;

    -- pre-drop temp table
    drop table if exists MyHierarchy;

    -- now, create it as the first level you want... 
    -- ie: a specific top level of all "no parent" entries
    -- or parameterize the function and ask for a specific "ID".
    -- add extra column as flag for next set of ID's to load into this.
    create table MyHierarchy as
    select 
            t1.IDMyTable,
            t1.Child AS Parent,
            @hierlvl as IDHierLevel,
            cast( t1.IDMyTable as char(100)) FullHierarchy
        from
            MyTable t1
        where
                t1.Parent is null
            OR t1.Parent = '';


    -- how many rows are we starting with at this tier level
    set @lastRowCount := ROW_COUNT();

    -- we need to have a "primary key", otherwise our UPDATE
    -- statement will nag about an unsafe update command
    alter table MyHierarchy add primary key (IDMyTable);


    -- NOW, keep cycling through until we get no more records
    while @lastRowCount > 0 do

        -- NOW, load in all entries found from full-set NOT already processed
        insert into MyHierarchy
            select 
                    t1.IDMyTable,
                    t1.Child as Parent,
                    h1.IDHierLevel +1 as IDHierLevel,
                    concat_ws( ',', h1.FullHierarchy, t1.IDMyTable ) as FullHierarchy
                from
                    MyTable t1
                        join MyHierarchy h1
                            on t1.Parent = h1.Parent
                    left join
                        MyHierarchy h2
                            on t1.IDMyTable = h2.IDMyTable
                where
                    h2.IDMyTable is null;


        set @lastRowCount := row_count();

        -- now, update the hierarchy level
        set @hierLevel := @hierLevel +1;

    end while;


    -- return the final set now
    select 
            *, concat( lpad( ' ', 1 + (IDHierLevel * 3 ), ' ' ), Parent ) as ShowHierarchy
        from MyHierarchy
        order by FullHierarchy;

END

首先为计算级别创建递归函数

function fn_CalcLevel(int @ID) 
As Begin
  Declare @ParentID int
  Select @ParentID = ParentID From Table1 where ID = @ID

  IF (@ParentID IS NULL) Return 1 Else Return 1+fn_CalcLevel(@ParentID)
End
然后创建如下所示的查询

Select *, fn_CalcLevel(Table1.ID) as Level
From Table1

如果您稍微调整一下您的表,您可以使用以下内容:

  SELECT Child,CONCAT(LPAD('',Clevel,' '),Child),etc from tablename
重新构造是,您需要将中的根节点作为父节点为0的行。您可以添加自己的父/子/C级别的订单,以获得所需的序列


我知道这是几年前的事了,但这可能会为其他人节省一些精力

这可能会对您有所帮助,正如其他人已经说过的,MySQL不支持递归函数,因此它不适合这种存储分层数据的邻接列表模型。您可能需要考虑重构数据以使用嵌套集合或闭包表。有关更多信息,请参阅。不一定是递归;只要语言有引用,就可以使用哈希表而无需递归。对对象的所有ID进行散列,让子数组引用其中的任何内容,您可以在一个
while
循环中完成所有操作。这有点离题,但您不只是将递归向下移动到语言中吗?在某些时候,确实需要找到每个节点的每个子节点?@Cylindric:显然,是的:)您需要递归来遍历树,例如在打印树时。我只是说你不需要它来构建它。现代的数据库管理系统一般都很擅长使用递归查询。MySQL只是落后了很多年
  SELECT Child,CONCAT(LPAD('',Clevel,' '),Child),etc from tablename