PostgreSql递归包含层级level

当在用oracle做递归时,往往会用到一个虚列level,表示当前的节点是第几层,现在PostgreSql的递归语法中(with recursive)中不包含层级列,当然你安装了PostgreSql的扩展也是可以的,就是安装cross这个脚本,具体在postgreSql安装目录项的share/extension下的tablefunc.sql,脚本。

由于在我实际的项目中不允许安装哪些脚本,因此只能先自定义一个函数,具体代码如下:

首先,创建自定义类型

CREATE TYPE public.type_custom_recursive AS (
  keyid TEXT,
  branch TEXT,
  parent_keyid TEXT,
  level TEXT
);

再创建函数:

CREATE OR REPLACE FUNCTION public.custom_recursive (
  table_name varchar,
  keyid text,
  parent_keyid text,
  keyid_value text,
  level integer,
  split_value varchar
)
RETURNS SETOF public.type_custom_recursive AS
$body$
declare
test_ type_custom_recursive;
    sql_text VARCHAR(1000);


BEGIN
-- i_id  as keyid,id as branch,level as level 
if $5 = 0 THEN
sql_text := 'select i_id::text as keyid,id::text as branch,i_parent_id::text as parent_keyid,level::text as level from (  
          with recursive temp as(
          select '||$2||' as i_id,'||$2||'::text as id ,'||$3||' from '|| $1 ||' where '||$2||' = cast('||$4||
          'as int) union all
          select b.'||$2||',cast (a.id || '''||split_value||''' || b.'||$2||' as text) as id,b.'||$3||'  from temp a,'||$1||' b
          where a.'||$2||' = b.'||$3||')select i_id,id,f_char_in_string(id,'''||$6||''')+1 as level,i_parent_id from temp
          ) t order by i_id';
          
else
sql_text := 'select i_id::text as keyid,id::text as branch,i_parent_id::text as parent_keyid,level::text as level from (  
          with recursive temp as(
          select '||$2||' as i_id,'||$2||'::text as id ,'||$3||' from '|| $1 ||' where '||$2||' = cast('||$4||
          'as int) union all
          select b.'||$2||',cast (a.id || '''||split_value||''' || b.'||$2||' as text) as id,b.'||$3||'  from temp a,'||$1||' b
          where a.'||$2||' = b.'||$3||')select i_id,id,f_char_in_string(id,'''||$6||''')+1 as level,i_parent_id from temp
          ) t  where level = '|| $5 ||' order by i_id';          
end if;


 for test_ in execute sql_text loop
          return next test_;
  end loop;          
end;
$body$
LANGUAGE 'plpgsql'
;

说明:

table_name varchar ,--需要递归的表名
  keyid text,--id
  parent_keyid text,--父id
  keyid_value text,--id的值
  level integer,--层级 0的话显示当前id下的所有节点
  split_value varchar --  分隔符比如"->"

注意这里的id默认都是为整型的,如果id是varchar型那么需要稍作修改的。

下面做个小例:

select * from custom_recursive('organization','i_id','i_parent_id','1',0,'->');

输出为

keyid,branch,parentkeyid,level

1 ,1,null,1

2,1->2,1,2

3,1->3,1,2

PostgreSQL 中处理涉及三个表的递归查询通常会使用 `WITH RECURSIVE` 子句。这种查询允许你在一张或多张表之间构建复杂的关系,并逐步迭代计算结果集。 ### 示例场景 假设我们有三张表: 1. **员工 (employees)** - 包含所有员工的基本信息。 ```sql CREATE TABLE employees ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, manager_id INT REFERENCES employees(id) ); ``` 2. **部门 (departments)** - 描述每个部门的信息及其主管(也是某个员工)。 ```sql CREATE TABLE departments ( dept_id SERIAL PRIMARY KEY, department_name TEXT NOT NULL, head_id INT REFERENCES employees(id) ON DELETE SET NULL ); ``` 3. **项目 (projects)** - 记录各个项目的负责人以及所在部门。 ```sql CREATE TABLE projects ( proj_id SERIAL PRIMARY KEY, project_name TEXT NOT NULL, leader_id INT REFERENCES employees(id), dept_id INT REFERENCES departments(dept_id) ); ``` #### 目标: 我们需要找出所有的“经理链”,即从最顶层领导开始到每一个直接下属、再依次往下直到最低级别的普通员工。这涉及到跨越上述表格之间的层级关系,特别是通过 `manager_id` 字段建立起来的层次结构。 ### SQL 查询示例 ```sql WITH RECURSIVE hierarchy AS ( -- 基础成员选择:找到初始节点(例如没有上级的总经理) SELECT e.id, e.name, ARRAY[e.name] as path, 0 as level FROM employees e WHERE e.manager_id IS NULL UNION ALL -- 迭代部分:添加下一层级的所有记录 SELECT e.id, e.name, h.path || e.name, h.level + 1 FROM employees e JOIN hierarchy h ON e.manager_id = h.id ) SELECT * FROM hierarchy; ``` 此查询首先选取了没有任何上司 (`manager_id`) 的顶级管理者作为起点;然后,在每次循环中加入该管理者的直属下级们,如此往复直至遍历完整个组织架构图。最终得到的结果集中包含了每一层管理人员的名字序列及他们各自所在的级别深度。 如果你希望进一步关联其他两张表获取更详细的数据,则可以在最后的选择语句里加上适当的JOIN操作。比如结合`departments` 表查看各部门负责人的管理层级等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值