在数据库的设计里面,经常使用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<Depart> getDepartTree(String parentId) throws SQLException {
List<Depart> departList = dao.queryList("depart.getChildDepart", parentId);
if (departList != null && departList.size() > 0) {
Iterator<Depart> 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的时候用得上,比如:
<select id="getList" resultMap="questionRM">
select * from ed_question where parentId is null
<dynamic prepend="and">
<isNotEmpty property="question.knowledgeId" prepend="and">
find_in_set(knowledgeId , knowledge_getChilds(#question.knowledgeId#))
</isNotEmpty>
<isNotEmpty property="question.quesTypeId" prepend="and">
quesTypeId = #question.quesTypeId#
</isNotEmpty>
<isNotEmpty property="question.status" prepend="and">
status = #question.status#
</isNotEmpty>
<isNotEmpty property="question.difficulty" prepend="and">
difficulty = #question.difficulty#
</isNotEmpty>
<isNotEmpty property="question.title" prepend="and">
title like concat('%',#question.title#,'%')
</isNotEmpty>
</dynamic>
order by createTime desc
</select>
分享到:
相关推荐
1. 查找树中的所有顶级父节点 2. 查找一个节点的直属子节点(所有儿子) 3. 查找一个节点的所有 直属子节点(所有后代) 4. 查找一个节点的直属父节点(父亲) 5. 查找一个节点的所有直属父节点(祖宗) 6. 查询一个...
//该节点中存放的对象 protected BinTreePosition parent;//父亲 protected BinTreePosition lChild;//左孩子 protected BinTreePosition rChild;//右孩子 protected int size;//后代数目 protected int height...
1、查询某节点下所有后代节点(包括各级父节点) // 查询id为101的所有后代节点,包含101在内的各级父节点 select t.* from SYS_ORG t start with id = '101' connect by parent_id = prior id 2、查询某节点下...
在无线传感器网络中,应用概率洪泛路由时,每个传感器节点收发信息具有随机性,在合理假设下,将网络中信息传输过程建立为一个分支过程模型,利用分支消亡概率和节点产生后代概率的关系,给出一种基于邻居节点数目的...
//返回当前节点后代元素的数目 public int getSize(); //在孩子发生变化后,更新当前节点及其祖先的规模 public void updateSize(); //返回当前节点的高度 public int getHeight(); //在孩子发生变化后,更新...
工程有这样的需求,在一个分级结构中,例如人类的家族,需要选 ...个节点,如果同辈节点有后代,择消选同辈节点及其后代,获取被勾选 的家族成员,激发 onCheckboxClick 事件;如果节点被消选,则消选其子 树。
对于每个节点,从该节点到其所有后代叶子节点的简单路径上,黑色节点的数量必须相同。 红黑树的平衡性质保证了在最坏情况下的时间复杂度为 O(log n),其中 n 是树中节点的数量。这使得红黑树成为一种广泛应用于高...
对于每个节点,从节点到后代叶的所有路径都包含相同数量的黑色节点。 红黑树是许多搜索树方案中的一种,它们是“平衡”的, 以便保证在最坏的情况下,基本的动态设置操作需要O(lg n)时间。 请注意,空叶节点或父...
//返回当前节点后代元素的数目,即以当前节点为根的子树的规模 public int getSize() { int size = 1;//当前节点也是自己的后代 TreeLinkedList subtree = firstChild;//从长子开始 while (null != subtree) ...
红黑树是一种自平衡二叉搜索树,它能够确保任何一个节点的两个子树的黑节点数量相同,从而保证树的最大高度约为log(n),使得查找、插入和删除操作的时间复杂度为O(log n)。以下是关于红黑树C++实现的一些补充说明: 1. ...
以功能方式检查节点是否是给定节点的后代。 安装 npm install fd-contains --save 用法 var contains = require ( 'fd-contains' ) , append = require ( 'fd-append' ) , elem = require ( 'fd-elem' ) , ...
XPath(XML Path Language)是一种基于 XML 的查询语言,用于在 XML 文档中选取节点或者节点集。XPath 使用路径表达式来选取 XML 文档中的节点或者节点集,这些路径表达式和我们在常规的电脑文件系统中看到的表达式...
//返回当前节点中存放的对象 public Object getElem() { return element; } //将对象obj存入当前节点,并返回此前的内容 public Object setElem(Object obj) { Object bak = element; element = obj; return bak...
33节点的前推后代法潮流程序,可以很好的使用,而且计算的结果正确
可制表的 小型实用程序,它返回包含节点内所有*可制表的DOM节点的数组。 *所有内容都有一些必要的警告,您可以通过阅读以下内容来了解这些警告。 以下内容被认为是可标签的: <button>元素<input>...
并指出只包含{ESC,/,//,[],*}的查询树模式的最小化问题的复杂度是指数级的,且当模式树是分支受限的时候,其最小化问题的复杂度是多项式时间的;最后给出了一个多项式时间的受限分支的模式树最小化算法。
XPath 是 W3C 的一个标准,它的主要目的是为了在 XML 文档节点树中定位节点。XPath 有两种版本:XPath1.0 和 XPath2.0。XPath2.0 是 XPath1.0 的超集,支持更加丰富的数据类型,并且保持了对 XPath1.0 的相对很好的...
在具有名称空间的Merkle树中,树中的每个非叶节点都包含在作为非叶节点后代的所有叶节点中找到的最低和最高名称空间标识符,此外还包含子树的子级的哈希值。节点。 这使得可以创建Merkle包含证明,以向验证者证明...
不平衡的二叉树:此类树中任何节点右侧的所有后代都不允许有子代,而左侧的所有后代则大约有2个子代。 任意树:这种树没有任何分支,这意味着它仅包含叶子和根。 因此,所有叶子都是根的子代。 注意:在我的代码...
.empty()是指对该节点后代的删除,结果是清空该节点(该节点里面已无元素)。 .remove()是指删除该节点,结果是删除该节点(该节点及其后代元素都将不存在)。 下面放代码来说明。 <!DOCTYPE html> <html> &...