我在其中一行中有一个字符串:
PID|1||123456789^^^^VV||PIZZA^KEVIN^^^^^L||98765432||
我已经编写了一个SQL查询,它将对此进行拆分
select regexp_substr('PPID|1||123456789^^^^VV||PIZZA^KEVIN^^^^^L||98765432||','[^|^]+', 1, level) col1 from dual
connect by regexp_substr('PID|1||123456789^^^^VV||PIZZA^KEVIN^^^^^L||98765432||', '[^|^]+', 1, level)
is not null
它的输出为:
col1
PID
1
123456789
VV
PIZZA
KEVIN
L
98765432
我正在寻找以下情况:
如果管道分开,则使用顺序 如果上限分开,则使用子序列
我正在寻找的输出:
col1 col_seq
PID PID00
1 PID01
(NULL) PID02
123456789 PID03-01
(NULL) PID03-02
(NULL) PID03-03
VV PID03-04
PIZZA PID04-01
KEVIN PID04-02
(NULL) PID04-03
(NULL) PID04-04
(NULL) PID04-05
(NULL) PID04-06
L PID04-07
(NULL) PID05
98765432 PID06
(NULL) PID07
(NULL) PID08
有人可以为此提供帮助吗?
答案 0 :(得分:2)
好的。这是简单的版本,可让您获得col1。如果您使用the splitting regexp substr from this question,效果会更好。
with t as (select 'PPID|1||123456789^^^^VV||PIZZA^KEVIN^^^^^L||98765432||' as str from dual)
select regexp_substr(t.str,'(.*?)(\||\^|$)', 1, level, null, 1) col1
from t
connect by level <= regexp_count(t.str, '(.*?)(\||\^|$)');
添加第二列会带来一些显着的复杂性。通过连接两个层次查询可能是一种优雅的方法,但是我做得不好,所以我只使用了一些解析函数。
with t as (select 'PPID|1||123456789^^^^VV||PIZZA^KEVIN^^^^^L||98765432||' as str from dual)
select col1,
'PID'
-- count pipes seen so far
|| trim(to_char(nvl(sum(case when sep = '|' then 1 else 0 end)
over (order by lev rows between unbounded preceding and 1 preceding)
,0)
,'00'))
-- count hats (within a partition defined by the number of pipes seen so far)
|| CASE when sep = '^' or lag(sep) over (order by lev) = '^' THEN
'-' || trim(to_char(row_number() over (partition by regexp_count(seen, '\|')
order by lev) - 1, '00'))
ELSE null end as col2
from (
select regexp_substr(t.str,'(.*?)(\||\^|$)', 1, level, null, 1) col1,
regexp_substr(t.str,'(.*?)(\||\^|$)', 1, level, null, 2) sep,
level as lev,
substr(t.str,1,regexp_instr(t.str,'(.*?)(\||\^|$)', 1, level, 0)) as seen
from t
connect by level <= regexp_count(t.str, '(.*?)(\||\^|$)')
) s
;
输出:
col1 col2
PPID PID00
1 PID01
PID02
123456789 PID03-01
PID03-02
PID03-03
PID03-04
VV PID03-05
PID04
PIZZA PID05-01
KEVIN PID05-02
PID05-03
PID05-04
PID05-05
PID05-06
L PID05-07
PID06
98765432 PID07
PID08
PID09
如果您有任何疑问,请告诉我。
编辑:好吧,regexp_substr和分层查询都非常慢。我用MT0's recursive CTE no-regex answer on this question重写了它。它仍然很草率,我敢肯定它可以清理。
WITH ex as (select 'PPID|1||123456789^^^^VV||PIZZA^KEVIN^^^^^L||98765432||' as str from dual),
t ( str, start_pos, end_pos ) AS
( SELECT str, 1, LEAST(INSTR(str, '|'),INSTR(str, '^')) FROM ex
UNION ALL
SELECT str,
end_pos + 1,
CASE WHEN INSTR(str, '|', end_pos + 1) > 0 and INSTR(str, '^', end_pos + 1) > 0 THEN
LEAST(INSTR(str, '|', end_pos + 1),INSTR(str, '^', end_pos + 1))
ELSE GREATEST(INSTR(str, '|', end_pos + 1),INSTR(str, '^', end_pos + 1)) END
FROM t
WHERE end_pos > 0
)
select col1,
'PID'
-- count pipes
|| trim(to_char(nvl(sum(case when rsep = '|' then 1 else 0 end)
over (order by start_pos rows between unbounded preceding and 1 preceding)
,0)
,'00'))
-- count hats
|| CASE when '^' in (lsep,rsep) THEN
'-' || trim(to_char(row_number() over (partition by (length(seen)-length(replace(seen, '|')))
order by start_pos), '00'))
ELSE null end
as col_seq
from (
SELECT str, start_pos, end_pos,
SUBSTR( str, start_pos, DECODE( end_pos, 0, LENGTH(str) + 1, end_pos ) - start_pos ) AS col1,
SUBSTR( str, start_pos-1, 1) as lsep, SUBSTR(str, DECODE( end_pos, 0, LENGTH(str) + 1, end_pos ), 1) as rsep,
SUBSTR( str, 1, DECODE( end_pos, 0, LENGTH(str) + 1, end_pos )-1 ) as seen
FROM t) s
order by start_pos;