Oracle: Recursive tree structure query function

overview

A tree structure usually consists of a root node, a parent node (PID), a child node (ID) and a leaf node.

query syntax

SELECT [LEVEL],*
FROM table_name
START WITH 条件1
CONNECT BY PRIOR 条件2
WHERE 条件3
ORDER BY 排序字段
Description: LEVEL—pseudo-column, used to indicate the level of the tree (for the level of the query result, the level of the root node is 1)
   Condition 1—the limiting condition of the root node, of course, the authority can also be relaxed to obtain multiple root nodes, That is to obtain multiple trees (ie: the condition after start with indicates where the recursion starts.)
   Condition 2—the connection condition, the purpose is to give the relationship between the parent and the child, and perform recursive queries based on this relationship (ie: when recursive The two data before and after are connected by condition 2)
   Condition 3—filter condition, to filter all returned records.
   SortField - Sorts all returned records

prior use

The position of prior determines the specific relationship during recursion or determines the retrieval order during query. Prior field 1=field 2 can be understood as field 1 of the current node is equal to field 2 of the next node.

Two ways of writing:

connect by prior PID=ID means to use a top-down search method (find the parent node first and then find the child node)
connect by PID=prior ID means use a bottom-up search method (find the leaf node first and then find the parent node)

example

grammar:

select
from table name t
where filter condition
start with t.PID=xx --start root node
connect by prior t.ID=t.PID
SELECT t.JGBH
  FROM GG_JGBH t
 where SYBZ = 1
 START WITH t.SJJG = (select SJJG from GG_JGBH where JGBH = '0001')
CONNECT BY PRIOR t.JGBH = t.SJJG

But the content of the upper-speed query does not include the data corresponding to the "start root node". At this time, my solution is to use OR to associate

select E_ADDRESS.*, (select jgmc from gg_jgbh where jgbh = account) jgmc
  from E_ADDRESS
 where ACCOUNT = (select SJJG from GG_JGBH where JGBH = '0001')
    or ACCOUNT in
       (SELECT t.JGBH
          FROM GG_JGBH t
         where SYBZ = 1
         START WITH t.SJJG = (select SJJG from GG_JGBH where JGBH = '0001')
        CONNECT BY PRIOR t.JGBH = t.SJJG)

example code

1. Query all descendant nodes under a node (including parent nodes at all levels)

// 查询id为101的所有后代节点,包含101在内的各级父节点
select t.* from SYS_ORG t start with id = '101' connect by parent_id = prior id

2. Query all descendant nodes under a node (excluding parent nodes at all levels)

select t.*
from SYS_ORG t
where not exists (select 1 from SYS_ORG s where s.parent_id = t.id)
start with id = '101'
connect by parent_id = prior id

3. Query all parent nodes of a node (all ancestor nodes , including yourself )

select t.*
  from SYS_ORG t
start with id = '401000501'
connect by prior parent_id = id

4. Query all sibling nodes (brothers) of a node

select * from SYS_ORG t
where exists (select * from SYS_ORG s where t.parent_id=s.parent_id and s.id='401000501')

5. Query all sibling nodes (family nodes) of a node, assuming no level field is set

Two techniques are used here, one is to use level to identify the level of each node in the table, and the other is to use the with syntax to simulate a temporary table with levels
with tmp as(
      select t.*, level leaf
      from SYS_ORG t
      start with t.parent_id = '0'
      connect by t.parent_id = prior t.id)
select *
      from tmp
where leaf = (select leaf from tmp where id = '401000501');

6. Query the parent node of a node and the parent's brother node (uncle node)

The query here is divided into the following steps.
First, use a temporary table plus a level for the entire table;
second, there are several types based on the level. For the example above, there are three situations:
(1) The current node is the top-level node, that is, the lev that is queried If the value is 1, then it has no parent node and will not be considered.
(2) The current node is a level 2 node, and the lev value obtained from the query is 2, so it is only necessary to ensure that the lev level is 1 is the sibling node of its superior node.
(3) In other cases, if the level is 3 or above, then the superior node (grandfather) of the superior node must be selected and found out, and then it is judged that the subordinate nodes of the grandfather are all sibling nodes belonging to the superior node of the node.
Finally, use union to combine the query results to form a result set.
with tmp as(
    select t.*, level lev
    from SYS_ORG t
    start with t.parent_id = '0'
    connect by t.parent_id = prior t.id)
select b.*
from tmp b,(select *
            from tmp
            where id = '401000501' and lev = '2') a
where b.lev = '1'
 
union all
 
select *
from tmp
where parent_id = (select distinct x.id
                from tmp x, --祖父
                     tmp y, --父亲
                     (select *
                      from tmp
                      where id = '401000501' and lev > '2') z --儿子
                where y.id = z.parent_id and x.id = y.parent_id); 

Guess you like

Origin blog.csdn.net/weixin_63610637/article/details/129539674