Usage of oracle connect by

1. Basic grammar

select * from table [start with condition1]
    connect by [prior] id=parentid
  • 1
  • 2

It is generally used to find data with a parent-child relationship, that is, data in a tree structure; the returned data can also clearly distinguish the data of each layer.

  • start with condition1 is used to limit the data of the first layer, or root node data; use this part of the data as the basis to find the second layer of data, then use the second layer of data to find the third layer of data and so on.

  • connect by [prior]  id=parentid This part is used to indicate what kind of relationship oracle looks for when looking for data; for example, when looking for data in the second layer, use the id  of the data in the first layer to track the records in the table. The parentid field is matched. If this condition is true, the data found is the second-level data. Similarly, the third-level and fourth-level data are searched... and so on.

There is another usage of prior:

select * from table [start with condition1]
    connect by id= [prior] parentid
  • 1
  • 2
  • This usage means looking up data from the bottom up, which can be understood as looking up the parent points from the leaf node, using the parentid of the first layer of data to match the id in the table record, and if the match is successful, the result is The second layer of data; the above is to find leaf nodes from the parent node down.

Other features

  1. The level keyword represents the level number in the tree structure; the first level is the number 1, and the second level is the number 2, increasing in turn.
  2. The CONNECT_BY_ROOT method can obtain the value of any field in the result set of the first-level rendezvous point; for example CONNECT_BY_ROOT (field name).

2. Here are two examples

2.1 Find leaf nodes from the root node

select t.*, level, CONNECT_BY_ROOT(id)
  from tab_test t
 start with t.id = 0
connect by prior t.id = t.fid;
  • 1
  • 2
  • 3
  • 4

write picture description here

2.2 Find upper nodes from leaf nodes

--第一种,修改prior关键字位置
select t.*, level, CONNECT_BY_ROOT(id)
  from tab_test t
 start with t.id = 4
connect by t.id = prior t.fid;

--第二种,prior关键字不动 调换后面的id=fid逻辑关系的顺序
select t.*, level, CONNECT_BY_ROOT(id)
  from tab_test t
 start with t.id = 4
connect by prior t.fid = t.id;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

write picture description here

3. Write some other usages that are commonly used

3.1 Generate a numeric sequence result set

  • Use rownum to implement a sequence of 1 to 10.
select rownum from dual connect by rownum<=10;
  • 1

The result set is as follows: 
write picture description here

  • Use level to implement a sequence of 1 to 10.
select level from dual connect by level<=10;
  • 1

The result set is as follows: 
write picture description here


3.2 Query the start time, end time, and number of weeks 12 weeks before the current time

select sysdate - (to_number(to_char(sysdate - 1, 'd')) - 1) -
       (rownum - 1) * 7 as startDate,
       sysdate + (7 - to_number(to_char(sysdate - 1, 'd'))) -
       (rownum - 1) * 7 as endDate,
       to_number(to_char(sysdate, 'iw')) - rownum + 1 as weekIndex
  from dual
connect by level<= 12;--将level改成rownum可以实现同样的效果
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

write picture description here

  • d is the day of the week
  • iw represents the week of the year

3.3 String segmentation, from one line to multiple lines

  1. For example, split a regular string such as 01#02#03#04
select REGEXP_SUBSTR('01#02#03#04', '[^#]+', 1, rownum) as newport 
    from dual connect by rownum <= REGEXP_COUNT('01#02#03#04', '[^#]+');
  • 1
  • 2

write picture description here


4. Data return strategy when the priority keyword is omitted

Construct a result set that contains two pieces of data; then query the data at levels 1, 2, and 3.

select t.*, level
  from (select 1 as num from dual
        union
        select 2 as num from dual
        ) t
connect by level <= 3;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

write picture description here

  1. From the results of the screenshot above, it can be seen that when the priority keyword is omitted, the data in the first layer is the initial result set, the data in the second layer is twice the initial result set, and the data in the third layer is three times the initial result set; suppose The number of records in the initial result set is n, and if the records in the m layer are queried, the number of records returned is: write picture description here records.

  2. Special attention should be paid when omitting the priority keyword to operate on data, the returned data may not be what you expect.


5. Let’s take a look at a few examples below, how to get the correct return result when the priority keyword is omitted for multiple result sets

5.1 There is the following result set 
write picture description here

Want to achieve 1-5, 20-30 data increment returns 1, 2, 3, 4, 5, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 a total of 16 records.

The SQL is as follows:

with temp0 as (
   select t.range_num,
          REGEXP_SUBSTR(t.range_num, '[^-]+', 1, 1) minNum, --最小num
          REGEXP_SUBSTR(t.range_num, '[^-]+', 1, 2) maxNum --最大num
     from range_table t
)

select t1.range_num ,t2.lv 
       from temp0 t1 join (
         select level lv from dual 
               CONNECT BY LEVEL <= (select max(maxNum) from temp0 )
          ) t2
          on (t2.lv >=t1.minNum and t2.lv <=t1.maxNum);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

write picture description here 
In the above sql, the maximum and minimum values ​​of range_num are first obtained, and then the connect by feature is used to generate a numerical sequence result set, and finally the two result sets are associated to obtain the required results.


5.2 Look at the slightly more complex result set, the output format is the same as above

write picture description here

The SQL is as follows:

with temp0 as (
  select b.range_num,
         REGEXP_SUBSTR(b.range_num, '[^,]+', 1, c.lv) as newport,
         REGEXP_SUBSTR(REGEXP_SUBSTR(b.range_num, '[^,]+', 1, c.lv), '[^-]+', 1, 1) as minNum,
         REGEXP_SUBSTR(REGEXP_SUBSTR(b.range_num, '[^,]+', 1, c.lv), '[^-]+', 1, 2) as maxNum
  from (select regexp_count(a.range_num, '[^,]+') AS cnt, 
               range_num
          from range_table a) b
  join (select LEVEL lv from dual CONNECT BY LEVEL <= 50) c 
  --这里的50表示的是range_num通过,分割后的数量,这里写死了50也可以sql动态max出来
        on c.lv <= b.cnt
)

select t1.range_num,t2.lv 
    from temp0 t1 
    join (
       select level lv from dual 
         CONNECT BY LEVEL <= (
             select max(to_number(maxNum)) from temp0 
         )
       ) t2 
    on ((t2.lv >=t1.minNum and t2.lv <=t1.maxNum));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

write picture description here


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324693292&siteId=291194637