Question:
Please tell me how to change the following code :
with temp as
(
select 108 Name, 'test' Project, 'string-1 , string-2 ; string-3' Error from dual
union all
select 109, 'test2', 'single string' from dual
)
select distinct
t.name, t.project,
trim(regexp_substr(t.error, '[^,;]+', 1, levels.column_value)) as error
from
temp t,
table(cast(multiset(select level from dual connect by level <= length (regexp_replace(t.error, '[^,;]+')) + 1) as sys.OdciNumberList)) levels
order by name;
into a universal function that takes a string as parameters (example: 'string--1, string-2 ; string-3 , string-4'
) and a regular expression that specifies the search for a string separator (example: '\s*[,;]\s*'
):
FUNCTION csvstr2tab(
p_str IN VARCHAR2,
p_sep_re IN VARCHAR2 DEFAULT '\s*[,;]\s*'
)
...
As an attempt of my own, here is a function that accomplishes the given task using a fixed line separator ( ','
):
create or replace type admin.strtable as table of varchar2(1000);
/
create or replace
function admin.str2tbl ( p_str in varchar2 ) return strtable
as
l_str long default p_str || ',';
l_n number;
l_data strtable := strtable();
begin
loop
l_n := instr( l_str, ',' );
exit when (nvl(l_n,0) = 0);
l_data.extend;
l_data( l_data.count ) := ltrim(rtrim(substr(l_str,1,l_n-1)));
l_str := substr( l_str, l_n+1 );
end loop;
return l_data;
end;
/
P.S. sql<>fiddle
UPDATE: I used the abbreviation CSV just to show that I'm dealing with strings that contain delimiter-separated substrings. In fact, the input strings are not necessarily "valid" CSVs at all.
Answer:
Try the reproducible example below (tested on version 12.2.0.1.0).
Schema preparation:
create table prjerr as
select 108 Name, 'test' Project, 'string-1 , string-2 ; string-3' Error from dual
union all
select 109, 'test2', 'single string' from dual
/
create or replace type tokenList is table of varchar2 (32767)
/
The function itself:
create or replace function csvstr2tab (
str varchar2, delimiter char := '\s*[,;]\s*') return tokenList is
pattern constant varchar2 (64) := '(.*?)(('||delimiter||')|($))';
tokens tokenList := tokenList ();
s varchar2 (96);
c int := 0;
begin
<<split>> loop c := c + 1;
s := regexp_substr (str, pattern, 1, c, null, 1);
exit split when s is null;
tokens.extend;
tokens(tokens.last) := s;
end loop;
return tokens;
end csvstr2tab;
/
Request and result:
select distinct name, project, t.column_value error
from prjerr p, csvstr2tab (p.error) t
order by name
/
NAME PROJE ERROR
---------- ----- ----------------
108 test string-1
108 test string-2
108 test string-3
109 test2 single string