2014-11-07 4 views
0

У меня есть имя таблицы pctable для родительской дочерней категории.Функция Mysql для родительского дочернего класса

id  parent_id 
    2322 0 
    2323 2322 
    2324 2322 
    2335 2322 
    2336 2322 
    2337 2322 
    4869 2322 
    5121 2322 
    6033 2322 
    6783 2322 
    1061 2323 
    4870 4869 
    4871 4869 
    4872 4869 
    4873 4869 
    6034 6033 
    6059 6033 

Я написал функцию mysql, чтобы получить все родительские дочерние элементы в разделительной запятой.

DELIMITER $$ 
    DROP FUNCTION IF EXISTS getBaseID $$ 
    CREATE FUNCTION getBaseID(articleID varchar(1024)) RETURNS TEXT 
    BEGIN 
     DECLARE x TEXT; 
     DECLARE y TEXT; 
     DECLARE rtext TEXT; 
     SET rtext = ""; 
     SET x = articleID; 
     sloop:LOOP 
      SET y = NULL; 
      SELECT SQL_CACHE GROUP_CONCAT(id) INTO y FROM pctable WHERE parent_id IN(x); 
      IF y IS NULL THEN 
       LEAVE sloop; 
      END IF; 
      SET x = y; 
      SET rtext = CONCAT(rtext,',',x); 
      ITERATE sloop; 
     END LOOP; 
     RETURN rtext; 
    END $$ 

    DELIMITER ; 

Когда я звоню, он возвращает неверные данные.

SELECT getBaseID(2322) FROM pctable LIMIT 1; 

Это возвращение

"2323,2324,2335,2336,2337,4869,5121,6033,6783,1061" 

Но он должен вернуть

"2323,2324,2335,2336,2337,4869,5121,6033,6783,1061,4870,4871,4872,4873,6034,6059" 
+0

Просто FYI вы должны смотреть на [Вложенные наборы] (http://stackoverflow.com/questions/5916482/php-mysql-best-tree-structure/ 5916536 # 5916536) для управления иерархическими данными. – webbiedave

ответ

1

Проблемы с кодом, что это

WHERE parent_id IN(x); 

когда x заменяется его значение actuall y становится следующим:

WHERE parent_id IN(',2323,2324,2335,2336,2337,4869,5121,6033,6783,1061'); 

Обратите внимание на отдельные кавычки. Вы думаете, что проходите серию чисел, но на самом деле вы передаете одну строку текста. Также обратите внимание, что с вашим кодом есть эта запятая впереди. Таким образом, даже если он не пройдет одну строку текста, он будет терпеть неудачу из-за синтаксической ошибки. Что вам нужно сделать, так это использовать динамический sql. Это возможно только в хранимых процедурах, а не в функциях.

Я переписан код для вас:

DELIMITER $$ 
DROP PROCEDURE IF EXISTS getBaseID $$ 
CREATE PROCEDURE getBaseID(IN articleID varchar(1024), OUT rtext TEXT) 
BEGIN 
    SET rtext = "-1"; 
    SET @x = articleID; 
    sloop:LOOP 
     SET @y = NULL; 
     SET @sql = CONCAT('SELECT GROUP_CONCAT(id) INTO @y FROM pctable WHERE parent_id IN(', @x, ');'); 
     PREPARE stmt FROM @sql; 
     EXECUTE stmt; 
     DEALLOCATE PREPARE stmt; 
     IF @y IS NULL THEN 
      LEAVE sloop; 
     END IF; 
     SET @x = @y; 
     SET rtext = CONCAT(rtext, ',', @x); 
     ITERATE sloop; 
    END LOOP; 
END $$ 

DELIMITER ; 

Я добавил

SET rtext = "-1"; 

преодолеть проблему с ведущей запятой, при условии, что у вас нет отрицательных id сек в таблице ,

Вы бы выполнить его с

CALL getBaseID(2322, @my_result); /*This executes the function and writes the result into the variable you pass as second parameter.*/ 
SELECT @my_result;    /*Then you select the result.*/ 
  • увидеть его работы вживую в sqlfiddle

И в качестве последней ноты, даже если она будет работать с вашей функции, не будет необходимо выбрать таблицу в этом случае. Вы можете выполнить его просто с помощью SELECT getBaseID(2322); Ничто в этой функции относится к строке или чем-то еще.

+0

Спасибо большое за помощь. Его работа :) –

1

Для первого цикла он найдет все записи, где parent_id - это IN ("2322"), который получает вас 2323,2324,2335,2336,2337,4869,5121,6033 и 6783. В следующем цикле он найдет все записи, где parent_id - IN ("2323,2324,2335,2336,2337,4869,5121,6033,6783"). В базовой теории это ничего не найдет, но я думаю, что, сравнивая INT с CHAR, он преобразует CHAR в INT, поэтому просто берёт все до первой запятой и эффективно ищет IN («2323»), который возвращает 1061. Поскольку 1061 не является родителем каких-либо записей, это означает, что y равно нулю в следующий раз вокруг цикла, поэтому он выпадает.

Быстрое решение будет: -

DELIMITER $$ 
    DROP FUNCTION IF EXISTS getBaseID $$ 
    CREATE FUNCTION getBaseID(articleID varchar(1024)) RETURNS TEXT 
    BEGIN 
     DECLARE x TEXT; 
     DECLARE y TEXT; 
     DECLARE rtext TEXT; 
     SET rtext = ""; 
     SET x = articleID; 
     sloop:LOOP 
      SET y = NULL; 
      SELECT SQL_CACHE GROUP_CONCAT(id) INTO y FROM pctable WHERE FIND_IN_SET(parent_id, x); 
      IF y IS NULL THEN 
       LEAVE sloop; 
      END IF; 
      SET x = y; 
      SET rtext = CONCAT(rtext,',',x); 
      ITERATE sloop; 
     END LOOP; 
     RETURN rtext; 
    END $$ 

    DELIMITER ; 
+0

Спасибо, что помогли мне. Работает :) –

Смежные вопросы