查询树中某节点所有的后代节点

在数据库的设计里面,经常使用parentId字段来构建树型的表结构,如部门、知识点等,数据举例:物电学院->自动化系->08自动化->08自动化一班,类似于这样的数据结构。如何查询某个节点下的所有子孙节点,在程序设计中有两种方法。以如下表结构做说明:

CREATE TABLE `basic_depart` (
  `departId` char(32) CHARACTER SET latin1 NOT NULL COMMENT '部门ID',
  `parentId` char(32) CHARACTER SET latin1 DEFAULT NULL COMMENT '父ID',
  `nodeType` tinyint(4) DEFAULT NULL COMMENT '0:无下级;1:有下级',
  `name` varchar(50) DEFAULT NULL COMMENT '部门名称',
  `telephone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `sortOrder` tinyint(4) DEFAULT NULL COMMENT '排序',
  `remark` varchar(1000) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`departId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

1、写一个递归函数来递归查询

public List getDepartTree(String parentId) throws SQLException {
  List departList = dao.queryList("depart.getChildDepart", parentId);

  if (departList != null && departList.size() > 0) {
   Iterator departIterator = departList.iterator();
   while (departIterator.hasNext()) {
    Depart depart = departIterator.next();
    depart.setSubDepartList(getDepartTree(depart.getDepartId()));
   }
  }

  return departList;
 }

  

递归函数比较简单,记住递归的2个要素:递归结束的条件和递归公式,一般不会有啥问题。

 

2、参考网上一哥们的思路,写一个求出所有子孙节点ID和自己的ID的mysql function

DROP FUNCTION IF EXISTS oes.depart_getChilds;
CREATE FUNCTION oes.`depart_getChilds`(rootId varchar(32)) RETURNS varchar(10000) CHARSET latin1
BEGIN
 DECLARE sTemp VARCHAR(10000);
  DECLARE sTempChd VARCHAR(10000);

  SET sTemp = rootId;
  SET sTempChd = rootId;
   
  WHILE sTempChd is not null DO
    SELECT group_concat(departId) INTO sTempChd FROM basic_depart where FIND_IN_SET(parentId,sTempChd) > 0;
    IF sTempChd is not null THEN 
     SET sTemp = concat(sTemp,',',sTempChd);
    END IF;
  END WHILE;
  RETURN sTemp;

END;

 

然后在程序或者ibatis里面设置查询条件类似下面:

select * from basic_depart where find_in_set(departId,depart_getChilds('root')) 

 

这里稍微说一下,我数据库的全套charset和collation都是UTF8。

 1.depart_getChilds函数RETURNS varchar(10000) CHARSET latin1,为什么要给返回值定义为charset latin1呢,因为貌似find_in_set函数的2个参数要求是latin1编码的(更正:不是find_in_set函数的问题,是departId字段的collation的设置问题)。不如此,就会报incorrect mix of collation的错误,为这个,浪费了我一个下午的时间。

 2.本来我想写一个通用的mysql函数,处理所有树型结构的table,把table的名称,parentId字段名称,Id字段名称通通作为参数传递给getChilds函数。结果天不遂人愿,mysql不支持在function和procedure里面使用动态sql,要命3000。

 3.为什么要第2个方法呢,一个是简单,一个是因为做ibatis的sqlmap的时候用得上,比如:

 

 

你可能感兴趣的:(J2EE)