项目中用户组,设备组采用树. 表结构是最简单的id+parentid来构造树.
功能点: 根据组id查询组下的所有子组.
此文首先给出最终版本,并分析如何实现.
--***** 数据库最终版本 *****--
CREATE OR REPLACE FUNCTION getchild_set(integer,integer) RETURNS SETOF integer AS
$BODY$
/*
根据组id查询所有子组.第二个参数为0:用户组; 为1:设备组
实现方式一: 返回integer集合类型(组id列表)
select getchild_set(1,0) as id
*/
DECLARE
ret integer;
BEGIN
RETURN NEXT $1;
IF $2 = 0 THEN
FOR ret IN SELECT groupid FROM som_user_group_info WHERE parentid = $1 LOOP
FOR ret IN select * from getchild_set(ret,0) LOOP
RETURN NEXT ret;
END LOOP;
END LOOP;
ELSE
FOR ret IN SELECT id FROM som_device_group_info WHERE parentid = $1 LOOP
FOR ret IN select * from getchild_set(ret,1) LOOP
RETURN NEXT ret;
END LOOP;
END LOOP;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql'
CREATE OR REPLACE FUNCTION getchild_str(integer,integer) RETURNS character varying AS
$BODY$
/*
根据组id查询所有子组.第二个参数为0:用户组; 为1:设备组
实现方式2: 返回逗号分隔的字符串
select getchild_str(1,0) as id
*/
declare
ret character varying := '';
tmp integer;
begin
IF $2 = 0 THEN
for tmp in select groupid from som_user_group_info where parentid = $1 loop
ret = ret || ',' || getchild_str(tmp,0);
end loop;
ELSE
for tmp in select id from som_device_group_info where parentid = $1 loop
ret = ret || ',' || getchild_str(tmp,1);
end loop;
END IF;
return $1 || ret;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE COST 100;
------------------------------------------------------
postgretql 函数递归:
--①取得一棵树的所有孩子节点,包括自己.
WITH RECURSIVE r AS (
SELECT * FROM tree WHERE id = 1
union ALL
SELECT tree.* FROM tree, r WHERE tree.parent = r.id
)
SELECT * FROM r ORDER BY id;
--根据组id 向下递归查找所有子组(也包括自己)--针对用户组的SQL
WITH RECURSIVE r AS (
SELECT * FROM som_user_group_info WHERE groupid = 1
UNION ALL
SELECT t.* FROM som_user_group_info t, r
WHERE t.parentid = r.groupid
)
SELECT * FROM r ORDER BY groupid
但是这样只能写在sqlmap里或者直接在postgretql的控制台执行.不能写成类似函数的形式来复用.
不过如果要复用的话,写在一个统一的sqlmap里不是也可以,然后在需要的地方引用这个SQL片段.
问题又来了,因为后端也要用到这些东西,最好能在数据库层进行存储,而不是写在前端.
采用函数有2种形式:一是返回集合类型;二是返回字符串类型.
--③
CREATE OR REPLACE FUNCTION public.query_child_menus (integer) RETURNS SETOF public.menus AS
DECLARE
itemid ALIAS FOR $1;
itemrecord record;
BEGIN
SELECT s.* INTO itemrecord FROM som_user_group_info s where id=itemid;
RETURN NEXT itemrecord;
IF (select count(1) from public.menus s where s.parent_id=itemrecord.id) >0 THEN
for itemrecord in SELECT s.* FROM public.menus s where s.parent_id=itemrecord.id LOOP
for itemrecord in select * from public.query_child_menus (itemrecord.id) LOOP
RETURN NEXT itemrecord;
end LOOP;
end LOOP;
END IF;
RETURN;
END;
LANGUAGE 'plpgsql'
--返回Table集合类型:(som_user_group_info)
--select * from getchild_table(1)
CREATE OR REPLACE FUNCTION getchild_table(integer)
RETURNS SETOF som_user_group_info AS
$BODY$
DECLARE
ret record;
BEGIN
select * into ret from som_user_group_info where groupid = $1;
RETURN NEXT ret;
IF (select count(1) from som_user_group_info where parentid = $1) > 0 THEN
FOR ret IN
select * from som_user_group_info where parentid = $1
LOOP
FOR ret IN
select * from getchild_table(ret.groupid)
LOOP
RETURN NEXT ret;
END LOOP;
END LOOP;
END IF;
END;
$BODY$
LANGUAGE 'plpgsql'
--返回RECORD集合类型:(groupid,parentid,groupname)
--select * from getchild_record(1) as foo(groupid integer,parentid integer,groupname varchar)
CREATE OR REPLACE FUNCTION getchild_record(integer)
RETURNS SETOF record AS
$BODY$
DECLARE
ret record;
BEGIN
select groupid,parentid,groupname into ret from som_user_group_info where groupid = $1;
RETURN NEXT ret;
FOR ret IN
SELECT groupid,parentid,groupname FROM som_user_group_info WHERE parentid = $1
LOOP
FOR ret IN
select * from getchild_record(ret.groupid) as foo(groupid integer,parentid integer,groupname varchar)
LOOP
RETURN NEXT ret;
END LOOP;
END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql'
--返回integer集合类型(groupid) usergroup版本
--select getchild_set(1)
CREATE OR REPLACE FUNCTION getchild_set(integer)
RETURNS SETOF integer AS
$BODY$
DECLARE
ret integer;
BEGIN
RETURN NEXT $1;
FOR ret IN
SELECT groupid FROM som_user_group_info WHERE parentid = $1
LOOP
FOR ret IN
select * from getchild_set(ret)
LOOP
RETURN NEXT ret;
END LOOP;
END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql'
--*****递归树设计*****--
CREATE OR REPLACE FUNCTION getchild_set(integer)
RETURNS SETOF integer AS
$BODY$
DECLARE
ret integer;
--ret1 integer;
BEGIN
RETURN NEXT $1;
FOR ret IN SELECT groupid FROM som_user_group_info WHERE parentid = $1 LOOP
--步骤1: 仅查询节点的下一级节点:直接返回遍历到的节点的子节点
--RETURN NEXT ret;
--Error: query has no destination for retult data
--select * from getchild_set(ret)
--RETURN NEXT ret;
--步骤2: 对子节点递归调用自身
FOR ret1 IN select * from getchild_set(ret) LOOP
RETURN NEXT ret1;
END LOOP;
--步骤3: ret1可以统一用ret变量
FOR ret IN select * from getchild_set(ret) LOOP
RETURN NEXT ret;
END LOOP;
END LOOP;
END;
$BODY$
LANGUAGE 'plpgsql'
--返回字符串形式
--步骤1:
CREATE OR REPLACE FUNCTION recursive_child(integer) RETURNS character varying AS
$BODY$
declare
ret character varying := '';
tmp integer;
begin
for tmp in select groupid from som_user_group_info where parentid = $1 loop
--ret = ret || ',' || tmp;
--ret = ret || recursive_child(tmp);
ret = ret || ',' || tmp || recursive_child(tmp);
end loop;
return ret;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE COST 100;
--步骤2: 上面的函数返回的字符串形式如:,2,3,4 再加上自身id在为:1,2,3,4
CREATE OR REPLACE FUNCTION getchild_str(integer)
RETURNS character varying AS
$BODY$
declare
begin
return $1 || recursive_child($1);
end;
$BODY$ LANGUAGE 'plpgsql' VOLATILE COST 100;
--将上面2个函数合为一个,并加入类型
CREATE OR REPLACE FUNCTION getchild_str(integer) RETURNS character varying AS
$BODY$
declare
ret character varying := '';
tmp integer;
begin
for tmp in select groupid from som_user_group_info where parentid = $1 loop
ret = ret || ',' || getchild_str(tmp);
end loop;
return $1 || ret;
end;
$BODY$
LANGUAGE 'plpgsql' VOLATILE COST 100;
------------------------------------------------------EOF
参考资料:
① http://blog.csdn.net/wh62592855/article/details/6443909
② http://www.postgretql.org/docs/8.4/static/queries-with.html
③ http://it.chinawin.net/database/article-facc.html
分享到:
相关推荐
3. 信息间的递归定义:信息和数据的关系是相互转化的,一次处理输出的信息可能成为下一次处理的原始数据,这种层次关系就形成了信息间的递归定义。 4. 信息反馈:控制系统的输入信息对受控对象产生作用后,将结果...
递归是函数自我调用的一种编程技术,通常用于解决可以分解为相似子问题的问题,但需要注意递归可能导致栈溢出等问题。 快速排序是高效的排序算法,采用分而治之的策略,将大问题分解为小问题来解决。快速排序在平均...
链表是由一系列节点组成,每个节点包含数据和指向下一个节点的指针。栈遵循“后进先出”(LIFO)原则,常用于递归和表达式求值。队列则遵循“先进先出”(FIFO)原则,适用于模拟各种等待队列,如打印机队列。 二、...
答:服务器端向客户端发送一个进程编号,一个程序域编号,以确定对象的位置。 24.在C#中,string str = null 与 string str = “” 请尽量使用文字或图象说明其中的区别。 答:string str = null 是不给他分配...
### 数据结构与算法学习笔记 #### 一、数据的逻辑结构与存储结构 - **数据的逻辑结构**:表示数据元素之间的逻辑关系,是独立于计算机的数学模型。 - **线性结构**:每个元素至多有一个直接前驱和一个直接后继,...
一种自平衡的树,用于数据库和文件系统的索引。 - **8.4.2 B+树的基本概念** 也是自平衡树,通常用于磁盘存储。 - **8.5 散列表** - **8.5.1 散列表的基本概念** 通过散列函数将键映射到数组索引上,以实现...
在处理多表关联的情况下,需要了解数据库设计中的关联关系,如一对一、一对多、多对多等。 ##### 部门表模块 部门表通常用于存储组织结构的信息。在实际开发中,可以通过实体类、DAO接口、服务接口等来实现对部门表...
- **单链表**:通过一系列节点表示,每个节点包含数据域和指向下一个节点的指针。 - **操作**:插入、删除、查找等基本操作。 #### 栈和队列 - **栈**:先进后出(FILO)的线性表,支持两种基本操作:入栈和出栈...
15. **向上与向下转型**:向上转型是将子类对象赋值给父类引用,向下转型则是将父类引用转换为子类对象,需要强制类型转换。 16. **动态方法绑定**:Java采用晚期绑定(或称为动态绑定),在运行时决定调用哪个方法...
- **删除文件夹及内容**: 递归删除文件夹下的所有文件和子文件夹。 ##### 8.4 文件列表和文件过滤器 - **列出文件**: `new File("dir").listFiles()` - **文件过滤器**: 使用`FilenameFilter`或`FileFilter`接口...
- **查找方法**:从根节点开始,根据值大小向下查找直至找到目标节点。 - **删除方法**:根据节点的不同情况采取不同的删除策略。 #### 应用场景 排序二叉树在多种场景下都有应用,例如: 1. **数据库索引**:...
在删除非空目录时,可能需要递归删除其中的所有文件和子目录。 ### 类与对象 #### 构造函数与析构函数 - **`__construct()`**:构造函数在创建新对象时自动调用。可以通过构造函数初始化对象的属性。 - **`__...
2. **链表**:链表是由节点(包含数据和指向下一个节点的指针)构成的数据结构。链表分为单链表、双链表和循环链表等,与数组相比,链表在插入和删除操作上更为灵活。 3. **栈**:栈是一种后进先出(LIFO)的数据...
每个节点包含数据和指向下一个节点的指针,支持高效插入和删除。C++中,`std::list`和`std::forward_list`是链表的实现。 3. **栈与队列**:栈是后进先出(LIFO)的数据结构,常用于表达式求值和递归等;队列是先进...
1. **数组**:数组是最基本的数据结构之一,它是一个有序的元素集合,每个元素都有一个唯一的索引。数组提供了直接访问任何位置元素的能力,但插入和删除操作通常效率较低。 2. **链表**:链表不同于数组,它的元素...
使用递归算法遍历目录树,可以获取目录下的所有文件和子目录,适用于搜索文件、清理目录等任务。 #### 十一、Properties类 `Properties`类继承自`Hashtable`,用于处理键值对配置信息,常用于读写.properties配置...
5. **堆(Heap)**:堆是一种特殊的树形数据结构,满足最大堆(父节点大于子节点)或最小堆(父节点小于子节点)的性质。堆常用于实现优先队列,也是排序算法(如堆排序)的基础。 6. **树(Tree)**:树是一种非...
此外,DNS还可以实现内部负载均衡,例如在一个应用访问数据库的场景下,配置数据库的域名而不是固定IP,当数据库需要更换服务器时,只需在DNS服务器上更新域名映射,无需改动应用配置。这种做法增强了系统的可维护性...
`count()`函数用于计算数组中的元素数量,它可以接受一个可选参数,如果设置为1,则会递归计算嵌套数组的元素数量。 `array_unique()`函数则是用来移除数组中重复的值,返回一个新的不包含重复值的数组。此外,我们...
在SQL Server 2005中,T-SQL(Transact-SQL)是用于操作数据库的主要编程语言。本文主要探讨了T-SQL查询中的几个关键概念,包括`SELECT`语句、嵌套查询、多重引用、Common Table Expressions (CTE)以及如何使用CTE...