(PHP) Рекурсия в процедуре MySQL.

ICEBeer
Дата: 26.07.2006 13:29:00
И так, есть процедура `buildStandartCategoryTree` которая рекурсивно бегает по
таблице и создаёт мне дерево.

В mysql, при вызове через консоль дерево строится красиво и исправно.
Но в php рекурсия при достижении самого глубокого места :), т.е. узла с самым высоким
level прекращает работу. В инете никакой сопутствующей инфы не нашёл.

Заранее спасибо.

Код процедуры

DELIMITER ;;
/*!50003 DROP PROCEDURE IF EXISTS `buildStandartCategoryTree` */;;
/*!50003 SET SESSION SQL_MODE="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER"*/;;
/*!50003 CREATE PROCEDURE `buildStandartCategoryTree`(IN p_id INT, isRecurse BOOL, nIteration INT)
BEGIN



  DECLARE n_id INT DEFAULT 0;

  DECLARE done INT DEFAULT 0;

  DECLARE c_standart CURSOR FOR SELECT `category_id` FROM `g_standart_cat` WHERE `category_pid` = p_id AND `category_id` != `category_pid`;

  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;



  IF(isRecurse = FALSE) THEN



    DROP TABLE IF EXISTS `_standart`;

    CREATE TEMPORARY TABLE `_standart` (

    `category_id` int(11) unsigned NOT NULL,

    `category_pid` int(11) unsigned NOT NULL default '0',

    `category_name` varchar(125) NOT NULL default '',

    `category_level` smallint(6) unsigned NOT NULL default '0',

    `category_description` VARCHAR(50000),

    `category_link` varchar(255) default NULL,

    `category_enb` enum('0','1') NOT NULL default '0',

    PRIMARY KEY  (`category_id`)

    ) ENGINE=HEAP;



    INSERT INTO `_standart` SELECT * FROM `g_standart_cat` WHERE `category_id` = p_id;



  END IF;



  SET @nAmount = (SELECT COUNT(`category_id`) FROM `g_standart_cat` WHERE `category_pid` = p_id AND `category_id` != `category_pid`);



  IF(nIteration > 0 AND @nAmount > 0) THEN



  OPEN c_standart;



  REPEAT

    FETCH c_standart INTO n_id;



    IF NOT done THEN

      INSERT INTO `_standart` SELECT * FROM `g_standart_cat` WHERE `category_id` = n_id AND `category_id` != `category_pid`;



      SET @nAmount = (SELECT COUNT(`category_id`) FROM `g_standart_cat` WHERE `category_pid` = n_id AND `category_id` != `category_pid`);



      IF(@nAmount > 0) THEN

        CALL `buildStandartCategoryTree`(n_id, TRUE, nIteration - 1);

      END IF;

    END IF;



  UNTIL done END REPEAT;



  CLOSE c_standart;

  END IF;



  SELECT * FROM `_standart`;

end */;;

Кому интересно в архиве лежат исходники.
ICEBeer
Дата: 26.07.2006 19:15:19
Форум мёртв? :(
ICEBeer
Дата: 26.07.2006 19:32:14
Вот данные...

LOCK TABLES `g_standart_cat` WRITE;
INSERT INTO `g_standart_cat` VALUES (1,0,'Type of cranes',1,'Type of cranes',NULL,'1'),(2,1,'Tower cranes',2,'Tower cranes',NULL,'1'),(3,2,'Top cranes',3,'top cranes',NULL,'1'),(4,2,'Self-electing cranes',3,'self-electing cranes',NULL,'1'),(5,1,'Mobile cranes',2,'Mobile cranes',NULL,'1'),(6,1,'Crawler cranes',2,'Crawler cranes',NULL,'1'),(7,1,'Gantry cranes',2,'Gantry cranes',NULL,'1'),(8,1,'Overhead cranes',2,'Overhead cranes',NULL,'1'),(9,1,'Rail mounted cranes',2,'Rail mounted cranes',NULL,'1'),(10,1,'Other cranes',2,'Other cranes',NULL,'1'),(11,0,'Services',1,'Services',NULL,'1'),(12,11,'Hire&rental',2,'Hire&rental','http://microsoft.com','1'),(13,11,'Repair&repaint',2,'Repair&repaint',NULL,'1'),(14,11,'Leasing',2,'Leasing',NULL,'1'),(15,0,'Spare parts',1,'Spare parts',NULL,'1'),(16,15,'Tower cranes',2,'Tower cranes',NULL,'1'),(17,16,'Top cranes',3,'top cranes',NULL,'1'),(18,16,'Self-electing cranes',3,'self-electing cranes',NULL,'1'),(19,15,'Mobile cranes',2,'Mobile cranes',NULL,'1'),(20,15,'Crawler cranes',2,'Crawler cranes',NULL,'1'),(21,15,'Gantry cranes',2,'Gantry cranes',NULL,'1'),(22,15,'Overhead cranes',2,'Overhead cranes',NULL,'1'),(23,15,'Rail mounted cranes',2,'Rail mounted cranes',NULL,'1'),(24,15,'Other cranes',2,'Other cranes',NULL,'1'),(25,27,'New category',2,'','','1'),(26,25,'Parent Category',2,'','','1'),(27,0,'Second Category',1,'Second Category','','0');
UNLOCK TABLES;
Anjey aka PM
Дата: 27.07.2006 00:42:31
скрипт создания таблицы выложи еще, вот тогда возможно ктото и поможет
ICEBeer
Дата: 27.07.2006 10:48:54
Срипт есть в архиве, но для особо ленивых вот.

DROP TABLE IF EXISTS `g_standart_cat`;
CREATE TABLE `g_standart_cat` (
  `category_id` int(11) unsigned NOT NULL auto_increment,
  `category_pid` int(11) unsigned NOT NULL default '0',
  `category_name` varchar(125) NOT NULL default '',
  `category_level` smallint(6) unsigned NOT NULL default '0',
  `category_description` text,
  `category_link` varchar(255) default NULL,
  `category_enb` enum('0','1') NOT NULL default '0',
  PRIMARY KEY  (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=cp1251;
ICEBeer
Дата: 27.07.2006 17:52:13
Всё, вопрос решён. Кому интересно, проблема была в следующем. MySQL некорректно работает с рекурсией, работа процедуры не останавливается при рекурсивном вызове, а выполняется до конца. И того я имею всего 1 SELECT.

Решается проблема очень просто, создаётся ещё одна процедура код которой

   DROP TABLE IF EXISTS `_standart`;
   CREATE TEMPORARY TABLE `_standart` (
   `category_id` int(11) unsigned NOT NULL,
   `category_pid` int(11) unsigned NOT NULL default '0',
   `category_name` varchar(125) NOT NULL default '',
   `category_level` smallint(6) unsigned NOT NULL default '0',
   `category_description` VARCHAR(50000),
   `category_link` varchar(255) default NULL,
   `category_enb` enum('0','1') NOT NULL default '0',
   PRIMARY KEY  (`category_id`)
   ) ENGINE=HEAP;

  INSERT INTO `_standart` SELECT * FROM `g_standart_cat` WHERE `category_id` = p_id;

  CALL `_buildStandartCategoryTree`(p_id, isRecurse, nIteration);

  SELECT * FROM `_standart`;
  DROP TABLE IF EXISTS `_standart`;

И всё, вуаля.