我有父子类别的表名pctable。
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 :(得分:1)
您的代码存在的问题是,
WHERE parent_id IN(x);
当x
替换为其值时实际上变为:
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.*/
最后一点,即使它适用于您的功能,在这种情况下您也不需要选择表格。你可以用SELECT getBaseID(2322);
简单地执行它。这个函数中的任何内容都不是指行或什么的。
答案 1 :(得分: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 ;