postgresql 遞迴處理/樹形結構處理/層次處理
阿新 • • 發佈:2018-12-16
os: ubuntu 16.04 postgresql: 9.6.8
基礎資料
機構tree結構表
postgres=# drop table xxorg; DROP TABLE postgres=# create table xxorg(id int8,name varchar(100),parentid int8); CREATE TABLE postgres=# insert into xxorg(id,name,parentid)values(1,'總部',0); insert into xxorg(id,name,parentid)values(10,'A分公司',1),(20,'B分公司',1); insert into xxorg(id,name,parentid)values(100,'AA經營部',10),(110,'AB經營部',10),(200,'BA經營部',20); insert into xxorg(id,name,parentid)values(1000,'AAA辦事處',100),(2000,'BAA辦事處',200); postgres=# \d List of relations Schema | Name | Type | Owner --------+------+-------+---------- public | xxorg | table | postgres (1 row) postgres=# postgres=# postgres=# select * from xxorg; id | name | parentid ------+-----------+---------- 1 | 總部 | 0 10 | A分公司 | 1 20 | B分公司 | 1 100 | AA經營部 | 10 110 | AB經營部 | 10 200 | BA經營部 | 20 1000 | AAA辦事處 | 100 2000 | BAA辦事處 | 200 (8 rows)
使用者機構表
postgres=# create table xxuserorg(userid varchar(100),orgid int8); CREATE TABLE postgres=# insert into xxuserorg(userid,orgid)values('user1',1),('user2',10),('user3',100),('user3',110),('user4',2000); INSERT 0 5 postgres=# postgres=# postgres=# select * from xxuserorg; userid | orgid --------+------- user1 | 1 user2 | 10 user3 | 100 user3 | 110 user4 | 2000 (5 rows)
初步寫法
向上遞迴
postgres=# with recursive tmp0 as ( SELECT id,name,parentid FROM xxorg where id = 200 --初始化節點 union SELECT t1.id,t1.name,t1.parentid FROM xxorg t1, tmp0 t0 where 1=1 and t1.id=t0.parentid ) SELECT id,name,parentid FROM tmp0; id | name | parentid -----+----------+---------- 200 | BA經營部 | 20 20 | B分公司 | 1 1 | 總部 | 0 (3 rows)
向下遞迴
postgres=# with recursive tmp0 as
(
SELECT id,name,parentid
FROM xxorg
where id = 200 --初始化節點
union
SELECT t1.id,t1.name,t1.parentid
FROM xxorg t1,
tmp0 t0
where 1=1
and t1.parentid=t0.id
)
SELECT id,name,parentid
FROM tmp0;
id | name | parentid
------+-----------+----------
200 | BA經營部 | 20
2000 | BAA辦事處 | 200
(2 rows)
不管是向上遞迴還是向下遞迴,符合需求的資料都篩選出來了,只是沒有層級,不太直觀。 最好有類似oracle 的 tree 結構的功能。
修改後寫法
向上遞迴 修改後
postgres=# with recursive tmp0(id,name,parentid,path,depth) as
(
SELECT id,name,parentid,array[id] as path,1 as depth
FROM xxorg
where id in (select orgid from xxuserorg where userid='user2') --初始化節點
union
SELECT t1.id,t1.name,t1.parentid,t1.id||t0.path,t0.depth+1 as depth
FROM xxorg t1,
tmp0 t0
where 1=1
and t1.id=t0.parentid
)
SELECT id,name,parentid,path,depth
FROM tmp0
order by depth desc,id
;
向下遞迴 修改後
postgres=# with recursive tmp0 as
(
SELECT id,name,parentid,array[id] as path,1 as depth
FROM xxorg
where id in (select orgid from xxuserorg where userid='user2') --初始化節點
union
SELECT t1.id,t1.name,t1.parentid,t0.path||t1.id,t0.depth+1 as depth
FROM xxorg t1,
tmp0 t0
where 1=1
and t1.parentid=t0.id
)
SELECT id,name,parentid,path,depth
FROM tmp0
order by depth,id
;
整合後的最終sql
postgres=# with recursive tmp0(id,name,parentid,path,depth) as (
--向上遞迴
SELECT id,name,parentid,array[id] as path,1 as depth
FROM xxorg
where id in (select orgid from xxuserorg where userid='user1') --初始化節點
union
SELECT t1.id,t1.name,t1.parentid,t1.id||t0.path,t0.depth+1 as depth
FROM xxorg t1,
tmp0 t0
where 1=1
and t1.id=t0.parentid
), tmp1 (id,name,parentid,path,depth) as (
--向下遞迴
SELECT id,name,parentid,array[id] as path,1 as depth
FROM xxorg
where id in (select orgid from xxuserorg where userid='user1') --初始化節點
union
SELECT t1.id,t1.name,t1.parentid,t0.path||t1.id,t0.depth+1 as depth
FROM xxorg t1,
tmp1 t0
where 1=1
and t1.parentid=t0.id
), tmp2 as (
--涉及到的所有有許可權的機構
SELECT id,name,parentid
FROM tmp0
union
SELECT id,name,parentid
FROM tmp1
), tmp3 (id,name,parentid,path,depth) as (
--再次對過濾出的機構向下遞迴,構成tree
SELECT id,name,parentid,array[id] as path,1 as depth
FROM tmp2
where parentid = 0 --這裡一定要為root節點,否則結果不對
union
SELECT t1.id,t1.name,t1.parentid,t0.path||t1.id,t0.depth+1 as depth
FROM tmp2 t1,
tmp3 t0
where 1=1
and t1.parentid=t0.id
)
select id,name,parentid,
'/'||array_to_string(path,'/') as path,
a0.depth,
lpad(a0.name, 2*a0.depth-1+length(a0.name),' ') as tree_name
from tmp3 a0
order by '/'||array_to_string(path,'/'),a0.depth
;
id | name | parentid | path | depth | tree_name
------+-----------+----------+----------------+-------+------------------
1 | 總部 | 0 | /1 | 1 | 總部
10 | A分公司 | 1 | /1/10 | 2 | A分公司
100 | AA經營部 | 10 | /1/10/100 | 3 | AA經營部
1000 | AAA辦事處 | 100 | /1/10/100/1000 | 4 | AAA辦事處
110 | AB經營部 | 10 | /1/10/110 | 3 | AB經營部
20 | B分公司 | 1 | /1/20 | 2 | B分公司
200 | BA經營部 | 20 | /1/20/200 | 3 | BA經營部
2000 | BAA辦事處 | 200 | /1/20/200/2000 | 4 | BAA辦事處
(8 rows)
完美。