MYSQL output in tree format OR Adding level (Parent-Child)

后端 未结 4 1850
失恋的感觉
失恋的感觉 2020-12-19 21:25

Below is what I have in my table.

myTable

++++++++++++++++++++
Parent   +  Child
++++++++++++++++++++
  C1     +    G1
  C1     +    G2
  C1     +          


        
4条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-19 22:09

    Although you can't do with a single query, you can do with a stored procedure... The only pre-requirement, you need to add 2 more records to your existing sample table to represent that "C1" and "C2" ARE the top level... Add a record where the "Parent" field is blank, and the child level is "C1" and another for "C2". This will "prepare" the top-most parent level. for subsequent hierarchy association, otherwise you have no starting "basis" of the top-level hierarchy. It also requires a "primary key" column (which I've created in this script as "IDMyTable" which is just 1-x sequential, but would assume you have an auto-increment column on your table to use instead).

    I've included all the output columns to show HOW it's built, but the premise of this routine is to create a table based on the expected column outputs, yet extra to hold the hierarchical representation downstream as it's being built. To MAKE SURE they retain the correct orientation as the layers get deeper, I'm concatinating the "ID" column -- you'll see how it works in the final result set.

    Then, in the final result set, I am pre-padding spaces based on however deep the hierarchy data is.

    The loop will add any records based on their parent being found in the preceding result set, but only if the ID has not already been added (prevent duplicates)...

    To see how the cyclical order was constantly appended to, you can run the last query WITHOUT the order by and see how each iteration qualified and added the previous hierarchy level was applied...

    -- --------------------------------------------------------------------------------
    -- 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
    

提交回复
热议问题