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; 

x은 그 버지니아와

WHERE parent_id IN(x); 

를 교체 할 때,

"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

은 그냥 참고하시기 바랍니다 당신이 http://stackoverflow.com/questions/5916482/php-mysql-best-tree-structure/ ([중첩 설정]을 조사한다 5916536 # 5916536)를 사용하여 계층 적 데이터를 관리합니다. – webbiedave

답변

1

코드의 문제가 반환해야 lue는 실제로 다음과 같습니다.

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 ; 

나는 당신이 당신의 표에 부정적인 id의이 없다고 가정, 선두 쉼표로 문제를 극복하기 위해

SET rtext = "-1"; 

추가 .

당신은 당신이없는 것,

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가 2323,2324,2335,2336,2337,4869,5121,6033 및 6783이되는 IN ("2322") 인 모든 레코드를 찾습니다. 다음 루프는 모두 parent_id가 IN 인 레코드 ("2323,2324,2335,2336,2337,4869,5121,6033,6783"). 기본 이론에서는 아무것도 찾을 수 없지만 INT와 CHAR를 비교할 때 CHAR를 INT로 변환하므로 모든 것을 첫 번째 쉼표로 가져 와서 효율적으로 IN ("2323")을 찾습니다. 1061은 어떤 레코드의 부모가 아니기 때문에 다음에 루프를 돌릴 때 y가 null이라는 의미이므로 삭제됩니다.

빠른 수정은 다음과 같습니다 -

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

도와 줘서 고마워요. 그것의 일 :) –

관련 문제