Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > Mysql Oracle中的Start with...Connect by

Mysql实现Oracle中的Start with...Connect by方式

作者:HNT_Wings

文章总结:作者在迁移数据库时,使用了Oracle的startwith进行树的递归查询,但遇到了一些问题,通过搜索和修改,作者成功地使用存储过程和预处理语句来实现动态查询,并解决了变量声明和预处理语句的问题

Mysql Oracle中的Start with...Connect by

工作需要,迁移数据库时发现使用了Oracle中的start with来进行树的递归查询,所以自己动手丰衣足食。

通过一番搜索后发现

大家的实现基本都是这样的:

CREATE FUNCTION queryChildrenAreaInfo(areaId INT)
RETURNS VARCHAR(4000)
BEGIN
DECLARE sTemp VARCHAR(4000);
DECLARE sTempChd VARCHAR(4000);

SET sTemp='$';
SET sTempChd = CAST(areaId AS CHAR);

WHILE sTempChd IS NOT NULL DO
SET sTemp= CONCAT(sTemp,',',sTempChd);
SELECT GROUP_CONCAT(id) INTO sTempChd FROM t_areainfo WHERE FIND_IN_SET(parentId,sTempChd)>0;
END WHILE;
RETURN sTemp;

但是这样的代码没法复用(而且我的navicat居然建立函数失败,或者各种错误,所以我使用了存储过程,效果一样),所以我们使用set和execute来进行语句的拼接和执行,

修改后

如下:

CREATE PROCEDURE getChildList
IN rootId DECIMAL(65),
IN tablesname VARCHAR(6000),
OUT sTemp VARCHAR(6000)
BEGIN
DECLARE sTempChd VARCHAR(4000);

SET sTemp='$';
SET sTempChd = CAST(rootId AS CHAR);

WHILE sTempChd IS NOT NULL DO
SET sTemp= CONCAT(sTemp,',',sTempChd);
set @sqlexe = concat("SELECT GROUP_CONCAT(id) INTO sTempChd FROM " , tablesname , " WHERE FIND_IN_SET(parentId,sTempChd)>0;")
prepare sqlexe from @sqlexe;
execute sqlexe;
END WHILE;
END;

这样一来我们就可以将表名作为参数传入,但是一番执行后,你会发现,哦豁,它居然报了这样一个错:

1327 - Undeclared variable: sTempChd;

这个低级错误困扰了我半天,我不是声明了sTempChd为declare吗?

答案很简单

预处理语句(也就是我们的prepare)中,只接受@声明的参数。因为在存储过程中,使用动态语句,预处理时,动态内容必须赋给一个会话变量,也就是@形式声明的变量,而declare声明的是存储过程变量,具体的内容涉及到更深的知识,我暂时无法找到原因。

前文是自上而下的查询,自下而上的查询其实很简单,只要替换一下参数和语句内容就可以了,

具体如下:

CREATE PROCEDURE `getParentList`( 
	IN rootId DECIMAL(65,0), 
	IN tablesname VARCHAR ( 500 ),
	OUT sTemp VARCHAR ( 6000 ) )
BEGIN
	DECLARE
		PARENTID DECIMAL(65);
	SET sTemp = '$';
	SET @sTempChd = cast(rootId as char);
	WHILE @sTempChd <> 0 DO
		SET sTemp = concat( sTemp, ',', @sTempChd );
		SET @sqlcmd = CONCAT("SELECT PARENTID into @sTempChd FROM " , tablesname , " WHERE CATEID = " , @sTempChd , ";");
		PREPARE stmt FROM @sqlcmd;
		EXECUTE stmt;
	END WHILE;
	DEALLOCATE PREPARE stmt;
END

别忘了,最后要执行一下deallocate语句,释放预处理sql,免得session的预处理语句过多,达到max_prepared_stmt_count的上限值。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文