Recursive mysql select?

前端 未结 2 424
挽巷
挽巷 2020-12-09 06:51

I saw this answer and i hope he is incorrect, just like someone was incorrect telling primary keys are on a column and I can\'t set it on multiple columns.

Here is m

2条回答
  •  Happy的楠姐
    2020-12-09 07:24

    I know there is probably better and more efficient answer above but this snippet gives a slightly different approach and provides both - ancestors and children.

    The idea is to constantly insert relative rowIds into temporary table, then fetch a row to look for it's relatives, rinse repeat until all rows are processed. Query can be probably optimized to use only 1 temporary table.

    Here is a working sqlfiddle example.

     CREATE TABLE Users
            (`id` int, `parent` int,`name` VARCHAR(10))//
    
        INSERT INTO Users
            (`parent`, `name`)
        VALUES  
            (1, NULL, 'root'),
            (2, 1, 'one'),
            (3, 1, '1down'),
            (4, 2, 'one_a'),
            (5, 4, 'one_a_b')//
    
        CREATE PROCEDURE getAncestors (in ParRowId int) 
        BEGIN 
           DECLARE tmp_parentId int;
           CREATE TEMPORARY TABLE tmp (parentId INT NOT NULL);
           CREATE TEMPORARY TABLE results (parentId INT NOT NULL);
           INSERT INTO tmp SELECT ParRowId;
           WHILE (SELECT COUNT(*) FROM tmp) > 0 DO
             SET tmp_parentId = (SELECT MIN(parentId) FROM tmp);
             DELETE FROM tmp WHERE parentId = tmp_parentId;
             INSERT INTO results SELECT parent FROM Users WHERE id = tmp_parentId AND parent IS NOT NULL;
             INSERT INTO tmp SELECT parent FROM Users WHERE id = tmp_parentId AND parent IS NOT NULL;
           END WHILE;
           SELECT * FROM Users WHERE id IN (SELECT * FROM results);
        END//
    
        CREATE PROCEDURE getChildren (in ParRowId int) 
        BEGIN 
           DECLARE tmp_childId int;
           CREATE TEMPORARY TABLE tmp (childId INT NOT NULL);
           CREATE TEMPORARY TABLE results (childId INT NOT NULL);
           INSERT INTO tmp SELECT ParRowId;
           WHILE (SELECT COUNT(*) FROM tmp) > 0 DO
             SET tmp_childId = (SELECT MIN(childId) FROM tmp);
             DELETE FROM tmp WHERE childId = tmp_childId;
             INSERT INTO results SELECT id FROM Users WHERE parent = tmp_childId;
             INSERT INTO tmp SELECT id FROM Users WHERE parent = tmp_childId;
           END WHILE;
           SELECT * FROM Users WHERE id IN (SELECT * FROM results);
        END//
    

    Usage:

    CALL getChildren(2);
    
        -- returns 
        id  parent  name
        4   2   one_a
        5   4   one_a_b
    
    
    CALL getAncestors(5);
    
        -- returns 
        id  parent  name
        1   (null)  root
        2   1   one
        4   2   one_a
    

提交回复
热议问题