mysql stored procedure that calls itself recursively

后端 未结 4 1934
太阳男子
太阳男子 2020-11-28 14:10

I have the following table:

id | parent_id | quantity
-------------------------
1  | null      | 5
2  | null      | 3
3  | 2         | 10
4  | 2         | 15         


        
相关标签:
4条回答
  • 2020-11-28 14:28

    How about avoiding procedures:

    SELECT quantity from (
     SELECT @rq:=parent_id as id, @val:=@val*quantity as quantity from (
      select * from testTable order by -id limit 1000000 # 'limit' is required for MariaDB if we want to sort rows in subquery
     ) t # we have to inverse ids first in order to get this working...
     join
     ( select @rq:= 6 /* example query */, @val:= 1 /* we are going to multiply values */) tmp
     where id=@rq
    ) c where id is null;
    

    Check out Fiddle!

    Note! this will not work if row's parent_id>id.

    Cheers!

    0 讨论(0)
  • 2020-11-28 14:34

    Take a look at Managing Hierarchical Data in MySQL by Mike Hillyer.

    It contains fully worked examples on dealing with hierarchical data.

    0 讨论(0)
  • 2020-11-28 14:42

    its work only in mysql version >= 5

    the stored procedure declaration is this,

    you can give it little improve , but this working :

    DELIMITER $$
    
    CREATE PROCEDURE calctotal(
       IN number INT,
       OUT total INT
    )
    
    BEGIN
    
       DECLARE parent_ID INT DEFAULT NULL ;
       DECLARE tmptotal INT DEFAULT 0;
       DECLARE tmptotal2 INT DEFAULT 0;
    
       SELECT parentid   FROM test   WHERE id = number INTO parent_ID;   
       SELECT quantity   FROM test   WHERE id = number INTO tmptotal;     
    
       IF parent_ID IS NULL
        THEN
        SET total = tmptotal;
       ELSE     
        CALL calctotal(parent_ID, tmptotal2);
        SET total = tmptotal2 * tmptotal;   
       END IF;
    
    END$$
    
    DELIMITER ;
    

    the calling is like (its important to set this variable) :

    SET @@GLOBAL.max_sp_recursion_depth = 255;
    SET @@session.max_sp_recursion_depth = 255; 
    
    CALL calctotal(6, @total);
    SELECT @total;
    
    0 讨论(0)
  • 2020-11-28 14:47
    DELIMITER $$
    CREATE DEFINER=`arun`@`%` PROCEDURE `recursivesubtree`( in iroot int(100) , in ilevel int(110) , in locid int(101) )
    BEGIN
      DECLARE irows,ichildid,iparentid,ichildcount,done INT DEFAULT 0;
    
      DECLARE cname VARCHAR(64);
      SET irows = ( SELECT COUNT(*) FROM account WHERE parent_id=iroot and location_id=locid );
      IF ilevel = 0 THEN
        DROP TEMPORARY TABLE IF EXISTS _descendants;
        CREATE TEMPORARY TABLE _descendants (
          childID INT, parentID INT, name VARCHAR(64), childcount INT, level INT
      );
      END IF;
      IF irows > 0 THEN
        BEGIN
          DECLARE cur CURSOR FOR
            SELECT
              f.account_id,f.parent_id,f.account_name,
              (SELECT COUNT(*) FROM account WHERE parent_id=t.account_id and location_id=locid ) AS childcount
            FROM account t JOIN account f ON t.account_id=f.account_id
            WHERE t.parent_id=iroot and t.location_id=locid 
            ORDER BY childcount<>0,t.account_id;
          DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
          OPEN cur;
          WHILE NOT done DO
            FETCH cur INTO ichildid,iparentid,cname,ichildcount;
            IF NOT done THEN
              INSERT INTO _descendants VALUES(ichildid,iparentid,cname,ichildcount,ilevel );
              IF ichildcount > 0 THEN
                CALL recursivesubtree( ichildid, ilevel + 1 );
              END IF;
            END IF;
          END WHILE;
          CLOSE cur;
        END;
      END IF;
    
      IF ilevel = 0 THEN
        -- Show result table headed by name that corresponds to iroot:
        SET cname = (SELECT account_name FROM account WHERE account_id=iroot and location_id=locid );
        SET @sql = CONCAT('SELECT   CONCAT(REPEAT(CHAR(36),2*level),IF(childcount,UPPER(name),name))',
                      ' AS ', CHAR(39),cname,CHAR(39),' FROM _descendants');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
        DROP PREPARE stmt;
      END IF;
    END$$
    DELIMITER ;
    
    0 讨论(0)
提交回复
热议问题