Test Data
--单条数据
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
)
select * from z_branch;
--多条数据
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
union all
select 'BR1002' brid, 'BR1002.BR1003' br_level from dual
union all
select 'BR1003' brid, 'BR1001.BR1003' br_level from dual
)
select * from z_branch;
1. Split a single string or a single piece of data
Can be used if there is only a single row of data in the table or to split a single string. Most of the talk on the Internet is about the splitting of a single piece of data, which is not applicable if it is splitting multiple pieces of data.
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
)
select level,
regexp_count(br_level, '\.') + 1,
regexp_substr(br_level, '[^.]+', 1, level) s_brid
from z_branch t
connect by level <= regexp_count(br_level, '\.') + 1;
regexp_count(br_level, '.') counts the number of characters.
regexp_substr(br_level, '[^.]+', 1, level) The br_level field uses characters from position 1. Split, level refers to the first level after split string
or
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
)
select level,
length(brid) - length(replace(brid, '.', '')) + 1,
regexp_substr(br_level, '[^.]+', 1, level) s_brid
from z_branch t
connect by level <= length(br_level) - length(replace(br_level, '.', '')) + 1;
error example
--结果不符合预期
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
union all
select 'BR1002' brid, 'BR1002.BR1003' br_level from dual
union all
select 'BR1003' brid, 'BR1001.BR1003' br_level from dual
)
select brid,
level,
regexp_count(br_level, '\.') + 1,
regexp_substr(br_level, '[^.]+', 1, level) s_brid
from z_branch t
connect by level <= regexp_count(br_level, '\.') + 1;
-- 不符合预期
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
union all
select 'BR1002' brid, 'BR1002.BR1003' br_level from dual
union all
select 'BR1003' brid, 'BR1001.BR1003' br_level from dual
)
select brid,
level,
regexp_count(br_level, '\.') + 1,
regexp_substr(br_level, '[^.]+', 1, level) s_brid
from z_branch t
where t.brid = 'BR1001'
connect by level <= regexp_count(br_level, '\.') + 1;
From the result, it can be seen that the data is generated first, and then filtered using the where condition
2. Multiple pieces of data splitting
1. Method 1
--正确
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
union all
select 'BR1002' brid, 'BR1002.BR1003' br_level from dual
union all
select 'BR1003' brid, 'BR1001.BR1003' br_level from dual
)
select brid,
level,
regexp_count(br_level, '\.') + 1 as row_cnt,
regexp_substr(br_level, '[^.]+', 1, level) as s_brid
from z_branch t
connect by level <= regexp_count(br_level, '\.') + 1
and t.brid = prior t.brid
and prior dbms_random.value > 0;
2. Method 2
--正确 借助伪列
with z_branch as(
select 'BR1001' brid, 'BR1001.BR1002.BR1003' br_level from dual
union all
select 'BR1002' brid, 'BR1002.BR1003' br_level from dual
union all
select 'BR1003' brid, 'BR1001.BR1003' br_level from dual
),
z_level as(
select level lv from dual connect by level < 10
)
select t.brid,
a.lv,
regexp_count(t.br_level, '\.') + 1 as row_cnt,
regexp_substr(t.br_level, '[^.]+', 1, a.lv) as s_brid
from z_branch t
inner join z_level a
on a.lv <= regexp_count(t.br_level, '\.') + 1;
Note: The number of pseudo-column rows created must be greater than the maximum number after string splitting. In this example, the maximum value after string splitting is 3, so as long as the number of pseudo-column rows is greater than 3.